Compare commits
106 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 | |||
| 7384118357 | |||
| 4d833a50e5 | |||
| 57b0fdac0b | |||
| e6bd94025f | |||
| 330a0414f0 | |||
| 5cc201b46d | |||
| 7e55d7765d | |||
| 8f942922fd | |||
| db5635e844 | |||
| 8bc952ba66 | |||
| 96cb3a07f4 | |||
| cd6a6258b6 | |||
| a0fa2c08ac | |||
| 6642b1647a | |||
| 5315caf830 | |||
| 872523b0f0 | |||
| 7bf99fb496 | |||
| a1047edddb | |||
| e956176872 | |||
| 6d2947b080 | |||
| fb304d6c27 | |||
| 903289caa4 | |||
| aff31ebd1b | |||
| b6773f6983 | |||
| 0d28eb31d2 |
@@ -1,15 +1,13 @@
|
|||||||
## Latest
|
[](https://travis-ci.org/haraldk/TwelveMonkeys)
|
||||||
|
[](https://maven-badges.herokuapp.com/maven-central/com.twelvemonkeys.imageio/imageio)
|
||||||
Master branch build status: [](https://travis-ci.org/haraldk/TwelveMonkeys)
|
[](https://stackoverflow.com/questions/tagged/twelvemonkeys)
|
||||||
|
[](https://paypal.me/haraldk76/100)
|
||||||
Latest release is TwelveMonkeys ImageIO [3.4.3](https://search.maven.org/search?q=g:com.twelvemonkeys.imageio%20AND%20v:3.4.3) (Jan. 9th, 2020).
|
|
||||||
[Release notes](https://github.com/haraldk/TwelveMonkeys/releases/latest).
|
|
||||||
|
|
||||||
## About
|
## About
|
||||||
|
|
||||||
TwelveMonkeys ImageIO is a collection of plugins and extensions for Java's ImageIO.
|
TwelveMonkeys ImageIO is a collection of plugins and extensions for Java's ImageIO.
|
||||||
|
|
||||||
These plugins extends the number of image file formats supported in Java, using the javax.imageio.* package.
|
These plugins extend the number of image file formats supported in Java, using the `javax.imageio.*` package.
|
||||||
The main purpose of this project is to provide support for formats not covered by the JRE itself.
|
The main purpose of this project is to provide support for formats not covered by the JRE itself.
|
||||||
|
|
||||||
Support for formats is important, both to be able to read data found
|
Support for formats is important, both to be able to read data found
|
||||||
@@ -19,246 +17,63 @@ The goal is to create a set of efficient and robust ImageIO plug-ins, that can b
|
|||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
## Features
|
## File formats supported
|
||||||
|
|
||||||
Mainstream format support
|
| Plugin | Format | Description | Read | Write | Metadata | Notes |
|
||||||
|
| ------ | -------- | ----------- |:----:|:-----:| -------- | ----- |
|
||||||
|
| Batik | **SVG** | Scalable Vector Graphics | âś” | - | - | 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 & Standard |
|
||||||
|
| | CUR | MS Windows Cursor Format | âś” | - | - |
|
||||||
|
| | ICO | MS Windows Icon Format | âś” | âś” | - |
|
||||||
|
| [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 | âś” | âś” | - |
|
||||||
|
| [IFF](https://github.com/haraldk/TwelveMonkeys/wiki/IFF-Plugin) | IFF | Commodore Amiga/Electronic Arts Interchange File Format | âś” | âś” | Standard |
|
||||||
|
| [JPEG](https://github.com/haraldk/TwelveMonkeys/wiki/JPEG-Plugin) | **JPEG** | Joint Photographers Expert Group | âś” | âś” | Native & Standard |
|
||||||
|
| | **JPEG Lossless** | | âś” | - | Native & Standard |
|
||||||
|
| [PCX](https://github.com/haraldk/TwelveMonkeys/wiki/PCX-Plugin) | PCX | ZSoft Paintbrush Format | âś” | - | Standard |
|
||||||
|
| | DCX | Multi-page PCX fax document | âś” | - | Standard |
|
||||||
|
| [PICT](https://github.com/haraldk/TwelveMonkeys/wiki/PICT-Plugin) | PICT | Apple Mac Paint Picture Format | âś” | - | - |
|
||||||
|
| [PNM](https://github.com/haraldk/TwelveMonkeys/wiki/PNM-Plugin) | PAM | NetPBM Portable Any Map | âś” | âś” | Standard |
|
||||||
|
| | PBM | NetPBM Portable Bit Map | âś” | - | Standard |
|
||||||
|
| | PGM | NetPBM Portable Grey Map | âś” | - | Standard |
|
||||||
|
| | PPM | NetPBM Portable Pix Map | âś” | âś” | Standard |
|
||||||
|
| | PFM | Portable Float Map | âś” | - | Standard |
|
||||||
|
| [PSD](https://github.com/haraldk/TwelveMonkeys/wiki/PSD-Plugin) | **PSD** | Adobe Photoshop Document | âś” | - | Native & Standard |
|
||||||
|
| | PSB | Adobe Photoshop Large Document | âś” | - | Native & Standard |
|
||||||
|
| [SGI](https://github.com/haraldk/TwelveMonkeys/wiki/SGI-Plugin) | SGI | Silicon Graphics Image Format | âś” | - | Standard |
|
||||||
|
| [TGA](https://github.com/haraldk/TwelveMonkeys/wiki/TGA-Plugin) | TGA | Truevision TGA Image Format | âś” | âś” | Standard |
|
||||||
|
|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 & Standard |
|
||||||
|
| | BigTIFF | | âś” | - | Native & Standard |
|
||||||
|
| [WebP](https://github.com/haraldk/TwelveMonkeys/wiki/WebP-Plugin) | **WebP** | Google WebP Format | âś” | - | Standard | In progress
|
||||||
|
| XWD | XWD | X11 Window Dump Format | âś” | - | Standard |
|
||||||
|
|
||||||
#### BMP - MS Windows/IBM OS/2 Device Independent Bitmap
|
|
||||||
|
|
||||||
* Read support for all known versions of the DIB/BMP format
|
|
||||||
* Indexed color, 1, 4 and 8 bit, including 4 and 8 bit RLE
|
|
||||||
* RGB, 16, 24 and 32 bit
|
|
||||||
* Embedded PNG and JPEG data
|
|
||||||
* Windows and OS/2 versions
|
|
||||||
* Native and standard metadata format
|
|
||||||
|
|
||||||
#### JPEG
|
**Important note on using Batik:** *Please read [The Apache™ XML Graphics Project - Security](http://xmlgraphics.apache.org/security.html),
|
||||||
|
and make sure you use version 1.14 or later.*
|
||||||
* Read support for the following JPEG "flavors":
|
|
||||||
* All JFIF compliant JPEGs
|
|
||||||
* All Exif compliant JPEGs
|
|
||||||
* YCbCr JPEGs without JFIF segment (converted to RGB, using embedded ICC profile)
|
|
||||||
* CMYK JPEGs (converted to RGB by default or as CMYK, using embedded ICC profile)
|
|
||||||
* Adobe YCCK JPEGs (converted to RGB by default or as CMYK, using embedded ICC profile)
|
|
||||||
* JPEGs containing ICC profiles with interpretation other than 'Perceptual' or class other than 'Display'
|
|
||||||
* JPEGs containing ICC profiles that are incompatible with stream data, corrupted ICC profiles or corrupted `ICC_PROFILE` segments
|
|
||||||
* JPEGs using non-standard color spaces, unsupported by Java 2D
|
|
||||||
* JPEGs with APP14/Adobe segments with length other than 14 bytes
|
|
||||||
* 8 bit JPEGs with 16 bit DQT segments
|
|
||||||
* Issues warnings instead of throwing exceptions in cases of corrupted or non-conformant data where ever the image
|
|
||||||
data can still be read in a reasonable way
|
|
||||||
* Thumbnail support:
|
|
||||||
* JFIF thumbnails (even if stream contains "inconsistent metadata")
|
|
||||||
* JFXX thumbnails (JPEG, Indexed and RGB)
|
|
||||||
* EXIF thumbnails (JPEG, RGB and YCbCr)
|
|
||||||
* Metadata support:
|
|
||||||
* JPEG metadata in both standard and native formats (even if stream contains "inconsistent metadata")
|
|
||||||
* `javax_imageio_jpeg_image_1.0` format (currently as native format, may change in the future)
|
|
||||||
* Non-conforming combinations of JFIF, Exif and Adobe markers, using "unknown" segments in the
|
|
||||||
"MarkerSequence" tag for the unsupported segments (for `javax_imageio_jpeg_image_1.0` format)
|
|
||||||
* Extended write support:
|
|
||||||
* CMYK JPEGs
|
|
||||||
* YCCK JPEGs in progress
|
|
||||||
|
|
||||||
#### JPEG-2000
|
|
||||||
|
|
||||||
* Possibly coming in the future, pending some license issues.
|
|
||||||
|
|
||||||
If you are one of the authors, or know one of the authors and/or the current license holders of either the original
|
|
||||||
jj2000 package or the JAI ImageIO project, please contact me (I've tried to get in touch in various ways,
|
|
||||||
without success so far).
|
|
||||||
|
|
||||||
Alternatively, if you have or know of a JPEG-2000 implementation in Java with a suitable license, get in touch. :-)
|
|
||||||
|
|
||||||
#### PNM - NetPBM Portable Any Map
|
|
||||||
|
|
||||||
* Read support for the following file types:
|
|
||||||
* PBM in 'P1' (ASCII) and 'P4' (binary) formats, 1 bit per pixel
|
|
||||||
* PGM in 'P2' (ASCII) and 'P5' (binary) formats, up to 16/32 bits per pixel
|
|
||||||
* PPM in 'P3' (ASCII) and 'P6' (binary) formats, up to 16/32 bits per pixel component
|
|
||||||
* PAM in 'P7' (binary) format up to 32 bits per pixel component
|
|
||||||
* Limited support for PFM in 'Pf' (gray) and 'PF' (RGB) formats, 32 bits floating point
|
|
||||||
* Write support for the following formats:
|
|
||||||
* PPM in 'P6' (binary) format
|
|
||||||
* PAM in 'P7' (binary) format
|
|
||||||
* Standard metadata support
|
|
||||||
|
|
||||||
#### PSD - Adobe Photoshop Document
|
|
||||||
|
|
||||||
* Read support for the following file types:
|
|
||||||
* Monochrome, 1 channel, 1 bit
|
|
||||||
* Indexed, 1 channel, 8 bit
|
|
||||||
* Gray, 1 channel, 8, 16 and 32 bit
|
|
||||||
* Duotone, 1 channel, 8, 16 and 32 bit
|
|
||||||
* RGB, 3-4 channels, 8, 16 and 32 bit
|
|
||||||
* CMYK, 4-5 channels, 8, 16 and 32 bit
|
|
||||||
* Read support for the following compression types:
|
|
||||||
* Uncompressed
|
|
||||||
* RLE (PackBits)
|
|
||||||
* Layer support
|
|
||||||
* Image layers only, in all of the above types
|
|
||||||
* Thumbnail support
|
|
||||||
* JPEG
|
|
||||||
* RAW (RGB)
|
|
||||||
* Support for "Large Document Format" (PSB)
|
|
||||||
* Native and Standard metadata support
|
|
||||||
|
|
||||||
#### TIFF - Aldus/Adobe Tagged Image File Format
|
|
||||||
|
|
||||||
* Read support for the following "Baseline" TIFF file types:
|
|
||||||
* Class B (Bi-level), all relevant compression types, 1 bit per sample
|
|
||||||
* Class G (Gray), all relevant compression types, 2, 4, 8, 16 or 32 bits per sample, unsigned integer
|
|
||||||
* Class P (Palette/indexed color), all relevant compression types, 1, 2, 4, 8 or 16 bits per sample, unsigned integer
|
|
||||||
* Class R (RGB), all relevant compression types, 8 or 16 bits per sample, unsigned integer
|
|
||||||
* Read support for the following TIFF extensions:
|
|
||||||
* Tiling
|
|
||||||
* Class F (Facsimile), CCITT Modified Huffman RLE, T4 and T6 (type 2, 3 and 4) compressions.
|
|
||||||
* LZW Compression (type 5)
|
|
||||||
* "Old-style" JPEG Compression (type 6), as a best effort, as the spec is not well-defined
|
|
||||||
* JPEG Compression (type 7)
|
|
||||||
* ZLib (aka Adobe-style Deflate) Compression (type 8)
|
|
||||||
* Deflate Compression (type 32946)
|
|
||||||
* Horizontal differencing Predictor (type 2) for LZW, ZLib, Deflate and PackBits compression
|
|
||||||
* Alpha channel (ExtraSamples type 1/Associated Alpha and type 2/Unassociated Alpha)
|
|
||||||
* CMYK data (PhotometricInterpretation type 5/Separated)
|
|
||||||
* YCbCr data (PhotometricInterpretation type 6/YCbCr) for JPEG
|
|
||||||
* CIELab data in TIFF, ITU and ICC variants (PhotometricInterpretation type 9, 10 and 11)
|
|
||||||
* Planar data (PlanarConfiguration type 2/Planar)
|
|
||||||
* ICC profiles (ICCProfile)
|
|
||||||
* BitsPerSample values up to 16 for most PhotometricInterpretations
|
|
||||||
* Multiple images (pages) in one file
|
|
||||||
* Write support for most "Baseline" TIFF options
|
|
||||||
* Uncompressed, PackBits, ZLib and Deflate
|
|
||||||
* Additional support for CCITT T4 and and T6 compressions.
|
|
||||||
* Additional support for LZW and JPEG (type 7) compressions
|
|
||||||
* Horizontal differencing Predictor (type 2) for LZW, ZLib, Deflate
|
|
||||||
* Native and Standard metadata support
|
|
||||||
|
|
||||||
Legacy formats
|
|
||||||
|
|
||||||
#### HDR - Radiance High Dynamic Range RGBE Format
|
|
||||||
|
|
||||||
* Read support for the most common RGBE (.hdr) format
|
|
||||||
* Samples are converted to 32 bit floating point (`float`) and normalized using a global tone mapper by default.
|
|
||||||
* Support for custom global tone mappers
|
|
||||||
* Alternatively, use a "null-tone mapper", for unnormalized data (allows local tone mapping)
|
|
||||||
* Unconverted RGBE samples accessible using `readRaster`
|
|
||||||
* Standard metadata support
|
|
||||||
|
|
||||||
#### IFF - Commodore Amiga/Electronic Arts Interchange File Format
|
|
||||||
|
|
||||||
* Legacy format, allows reading popular image format from the Commodore Amiga computer.
|
|
||||||
* Read support for the following file types:
|
|
||||||
* ILBM Indexed color, 1-8 interleaved bit planes, including 6 bit EHB
|
|
||||||
* ILBM Gray, 8 bit interleaved bit planes
|
|
||||||
* ILBM RGB, 24 and 32 bit interleaved bit planes
|
|
||||||
* ILBM HAM6 and HAM8
|
|
||||||
* PBM Indexed color, 1-8 bit,
|
|
||||||
* PBM Gray, 8 bit
|
|
||||||
* PBM RGB, 24 and 32 bit
|
|
||||||
* PBM HAM6 and HAM8
|
|
||||||
* Write support
|
|
||||||
* ILBM Indexed color, 1-8 bits per sample, 8 bit gray, 24 and 32 bit true color.
|
|
||||||
* Support for the following compression types (read/write):
|
|
||||||
* Uncompressed
|
|
||||||
* RLE (PackBits)
|
|
||||||
|
|
||||||
#### PCX - ZSoft Paintbrush Format
|
|
||||||
|
|
||||||
* Read support for the following file types:
|
|
||||||
* Indexed color, 1, 2, 4 or 8 bits per pixel, bit planes or interleaved
|
|
||||||
* Grayscale, 8 bits per pixel
|
|
||||||
* Color (RGB), 8 bits per pixel component
|
|
||||||
* Read support for DCX (multi-page) fax format, containing any of the above types
|
|
||||||
* Support for the following compression types:
|
|
||||||
* Uncompressed (experimental)
|
|
||||||
* RLE compressed
|
|
||||||
* Standard metadata support
|
|
||||||
|
|
||||||
#### PICT - Apple Mac Paint Picture Format
|
|
||||||
|
|
||||||
* Legacy format, especially useful for reading OS X clipboard data.
|
|
||||||
* Read support for the following file types:
|
|
||||||
* QuickDraw (format support is not complete, but supports most OS X clipboard data as well as RGB pixel data)
|
|
||||||
* QuickDraw bitmap
|
|
||||||
* QuickDraw pixmap
|
|
||||||
* QuickTime stills
|
|
||||||
* Write support for RGB pixel data:
|
|
||||||
* QuickDraw pixmap
|
|
||||||
|
|
||||||
#### SGI - Silicon Graphics Image Format
|
|
||||||
|
|
||||||
* Read support for the following file types:
|
|
||||||
* 1, 2, 3 or 4 channel image data
|
|
||||||
* 8 or 16 bits per pixel component
|
|
||||||
* Support for the following compression types:
|
|
||||||
* Uncompressed
|
|
||||||
* RLE compressed
|
|
||||||
* Standard metadata support
|
|
||||||
|
|
||||||
#### TGA - Truevision TGA Image Format
|
|
||||||
|
|
||||||
* Read support for the following file types:
|
|
||||||
* ColorMapped
|
|
||||||
* Monochrome
|
|
||||||
* TrueColor
|
|
||||||
* Support for the following compression types:
|
|
||||||
* Uncompressed
|
|
||||||
* RLE compressed
|
|
||||||
* Standard metadata support
|
|
||||||
* Write support
|
|
||||||
|
|
||||||
Icon/other formats
|
|
||||||
|
|
||||||
#### ICNS - Apple Icon Image
|
|
||||||
|
|
||||||
* Read support for the following icon types:
|
|
||||||
* All known "native" icon types
|
|
||||||
* Large PNG encoded icons
|
|
||||||
* Large JPEG 2000 encoded icons (requires JPEG 2000 ImageIO plugin or fallback to `sips` command line tool)
|
|
||||||
* Write support for PNG encoded icons
|
|
||||||
|
|
||||||
#### ICO & CUR - MS Windows Icon and Cursor Formats
|
|
||||||
|
|
||||||
* Read support for the following file types:
|
|
||||||
* ICO Indexed color, 1, 4 and 8 bit
|
|
||||||
* ICO RGB, 16, 24 and 32 bit
|
|
||||||
* CUR Indexed color, 1, 4 and 8 bit
|
|
||||||
* CUR RGB, 16, 24 and 32 bit
|
|
||||||
* Write support
|
|
||||||
* *3.1* Note: These formats are now part of the BMP plugin
|
|
||||||
|
|
||||||
#### Thumbs.db - MS Windows Thumbs DB
|
|
||||||
|
|
||||||
* Read support
|
|
||||||
|
|
||||||
Other formats, using 3rd party libraries
|
|
||||||
|
|
||||||
#### SVG - Scalable Vector Graphics
|
|
||||||
|
|
||||||
* Read-only support using Batik
|
|
||||||
|
|
||||||
#### WMF - MS Windows MetaFile
|
|
||||||
|
|
||||||
* Limited read-only support using Batik
|
|
||||||
|
|
||||||
**Important note on using Batik:** *Please read [The Apache™ XML Graphics Project - Security](http://xmlgraphics.apache.org/security.html), and make sure you use
|
|
||||||
either version 1.6.1, 1.7.1 or 1.8+.*
|
|
||||||
|
|
||||||
|
Note that GIF, PNG and WBMP formats are already supported through the ImageIO API, using the
|
||||||
|
[JDK standard plugins](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/package-summary.html).
|
||||||
|
For BMP, JPEG, and TIFF formats the TwelveMonkeys plugins provides extended format support and additional features.
|
||||||
|
|
||||||
## Basic usage
|
## Basic usage
|
||||||
|
|
||||||
Most of the time, all you need to do is simply include the plugins in your project and write:
|
Most of the time, all you need to do is simply include the plugins in your project and write:
|
||||||
|
|
||||||
BufferedImage image = ImageIO.read(file);
|
```java
|
||||||
|
BufferedImage image = ImageIO.read(file);
|
||||||
|
```
|
||||||
|
|
||||||
This will load the first image of the file, entirely into memory.
|
This will load the first image of the file, entirely into memory.
|
||||||
|
|
||||||
The basic and simplest form of writing is:
|
The basic and simplest form of writing is:
|
||||||
|
|
||||||
if (!ImageIO.write(image, format, file)) {
|
```java
|
||||||
// Handle image not written case
|
if (!ImageIO.write(image, format, file)) {
|
||||||
}
|
// Handle image not written case
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
This will write the entire image into a single file, using the default settings for the given format.
|
This will write the entire image into a single file, using the default settings for the given format.
|
||||||
|
|
||||||
@@ -269,50 +84,44 @@ The plugins are discovered automatically at run time. See the [FAQ](#faq) for mo
|
|||||||
If you need more control of read parameters and the reading process, the common idiom for reading is something like:
|
If you need more control of read parameters and the reading process, the common idiom for reading is something like:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
// Create input stream
|
// Create input stream (in try-with-resource block to avoid leaks)
|
||||||
ImageInputStream input = ImageIO.createImageInputStream(file);
|
try (ImageInputStream input = ImageIO.createImageInputStream(file)) {
|
||||||
|
// Get the reader
|
||||||
|
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
|
||||||
|
|
||||||
|
if (!readers.hasNext()) {
|
||||||
|
throw new IllegalArgumentException("No reader for: " + file);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageReader reader = readers.next();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Get the reader
|
reader.setInput(input);
|
||||||
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
|
|
||||||
|
|
||||||
if (!readers.hasNext()) {
|
// Optionally, listen for read warnings, progress, etc.
|
||||||
throw new IllegalArgumentException("No reader for: " + file);
|
reader.addIIOReadWarningListener(...);
|
||||||
}
|
reader.addIIOReadProgressListener(...);
|
||||||
|
|
||||||
ImageReader reader = readers.next();
|
ImageReadParam param = reader.getDefaultReadParam();
|
||||||
|
|
||||||
try {
|
// Optionally, control read settings like sub sampling, source region or destination etc.
|
||||||
reader.setInput(input);
|
param.setSourceSubsampling(...);
|
||||||
|
param.setSourceRegion(...);
|
||||||
|
param.setDestination(...);
|
||||||
|
// ...
|
||||||
|
|
||||||
// Optionally, listen for read warnings, progress, etc.
|
// Finally read the image, using settings from param
|
||||||
reader.addIIOReadWarningListener(...);
|
BufferedImage image = reader.read(0, param);
|
||||||
reader.addIIOReadProgressListener(...);
|
|
||||||
|
|
||||||
ImageReadParam param = reader.getDefaultReadParam();
|
// Optionally, read thumbnails, meta data, etc...
|
||||||
|
int numThumbs = reader.getNumThumbnails(0);
|
||||||
// Optionally, control read settings like sub sampling, source region or destination etc.
|
// ...
|
||||||
param.setSourceSubsampling(...);
|
|
||||||
param.setSourceRegion(...);
|
|
||||||
param.setDestination(...);
|
|
||||||
// ...
|
|
||||||
|
|
||||||
// Finally read the image, using settings from param
|
|
||||||
BufferedImage image = reader.read(0, param);
|
|
||||||
|
|
||||||
// Optionally, read thumbnails, meta data, etc...
|
|
||||||
int numThumbs = reader.getNumThumbnails(0);
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
// Dispose reader in finally block to avoid memory leaks
|
|
||||||
reader.dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
// Close stream in finally block to avoid resource leaks
|
// Dispose reader in finally block to avoid memory leaks
|
||||||
input.close();
|
reader.dispose();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Query the reader for source image dimensions using `reader.getWidth(n)` and `reader.getHeight(n)` without reading the
|
Query the reader for source image dimensions using `reader.getWidth(n)` and `reader.getHeight(n)` without reading the
|
||||||
@@ -324,86 +133,56 @@ It's also possible to read multiple images from the same file in a loop, using `
|
|||||||
If you need more control of write parameters and the writing process, the common idiom for writing is something like:
|
If you need more control of write parameters and the writing process, the common idiom for writing is something like:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
// Get the writer
|
// Get the writer
|
||||||
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(format);
|
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(format);
|
||||||
|
|
||||||
if (!writers.hasNext()) {
|
if (!writers.hasNext()) {
|
||||||
throw new IllegalArgumentException("No writer for: " + format);
|
throw new IllegalArgumentException("No writer for: " + format);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageWriter writer = writers.next();
|
ImageWriter writer = writers.next();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Create output stream
|
// Create output stream (in try-with-resource block to avoid leaks)
|
||||||
ImageOutputStream output = ImageIO.createImageOutputStream(file);
|
try (ImageOutputStream output = ImageIO.createImageOutputStream(file)) {
|
||||||
|
writer.setOutput(output);
|
||||||
try {
|
|
||||||
writer.setOutput(output);
|
// Optionally, listen to progress, warnings, etc.
|
||||||
|
|
||||||
// Optionally, listen to progress, warnings, etc.
|
ImageWriteParam param = writer.getDefaultWriteParam();
|
||||||
|
|
||||||
ImageWriteParam param = writer.getDefaultWriteParam();
|
// Optionally, control format specific settings of param (requires casting), or
|
||||||
|
// control generic write settings like sub sampling, source region, output type etc.
|
||||||
// Optionally, control format specific settings of param (requires casting), or
|
|
||||||
// control generic write settings like sub sampling, source region, output type etc.
|
// Optionally, provide thumbnails and image/stream metadata
|
||||||
|
writer.write(..., new IIOImage(..., image, ...), param);
|
||||||
// Optionally, provide thumbnails and image/stream metadata
|
|
||||||
writer.write(..., new IIOImage(..., image, ...), param);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
// Close stream in finally block to avoid resource leaks
|
|
||||||
output.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
// Dispose writer in finally block to avoid memory leaks
|
|
||||||
writer.dispose();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
// Dispose writer in finally block to avoid memory leaks
|
||||||
|
writer.dispose();
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
For more advanced usage, and information on how to use the ImageIO API, I suggest you read the
|
For more advanced usage, and information on how to use the ImageIO API, I suggest you read the
|
||||||
[Java Image I/O API Guide](http://docs.oracle.com/javase/7/docs/technotes/guides/imageio/spec/imageio_guideTOC.fm.html)
|
[Java Image I/O API Guide](http://docs.oracle.com/javase/7/docs/technotes/guides/imageio/spec/imageio_guideTOC.fm.html)
|
||||||
from Oracle.
|
from Oracle.
|
||||||
|
|
||||||
|
#### Adobe Clipping Path support
|
||||||
|
|
||||||
#### Deploying the plugins in a web app
|
```java
|
||||||
|
import com.twelvemonkeys.imageio.path.Paths;
|
||||||
|
|
||||||
Because the `ImageIO` plugin registry (the `IIORegistry`) is "VM global", it doesn't by default work well with
|
...
|
||||||
servlet contexts. This is especially evident if you load plugins from the `WEB-INF/lib` or `classes` folder.
|
|
||||||
Unless you add `ImageIO.scanForPlugins()` somewhere in your code, the plugins might never be available at all.
|
|
||||||
|
|
||||||
In addition, servlet contexts dynamically loads and unloads classes (using a new class loader per context).
|
try (ImageInputStream stream = ImageIO.createImageInputStream(new File("image_with_path.jpg")) {
|
||||||
If you restart your application, old classes will by default remain in memory forever (because the next time
|
BufferedImage image = Paths.readClipped(stream);
|
||||||
`scanForPlugins` is called, it's another `ClassLoader` that scans/loads classes, and thus they will be new instances
|
|
||||||
in the registry). If a read is attempted using one of the remaining "old" readers, weird exceptions
|
|
||||||
(like `NullPointerException`s when accessing `static final` initialized fields or `NoClassDefFoundError`s
|
|
||||||
for uninitialized inner classes) may occur.
|
|
||||||
|
|
||||||
To work around both the discovery problem and the resource leak,
|
// Do something with the clipped image...
|
||||||
it is *strongly recommended* to use the `IIOProviderContextListener` that implements
|
}
|
||||||
dynamic loading and unloading of ImageIO plugins for web applications.
|
|
||||||
|
|
||||||
```xml
|
|
||||||
<web-app ...>
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
<listener>
|
|
||||||
<display-name>ImageIO service provider loader/unloader</display-name>
|
|
||||||
<listener-class>com.twelvemonkeys.servlet.image.IIOProviderContextListener</listener-class>
|
|
||||||
</listener>
|
|
||||||
|
|
||||||
...
|
|
||||||
|
|
||||||
</web-app>
|
|
||||||
```
|
```
|
||||||
|
See [Adobe Clipping Path support on the Wiki](https://github.com/haraldk/TwelveMonkeys/wiki/Photoshop-Clipping-Path-support) for more details and example code.
|
||||||
|
|
||||||
Loading plugins from `WEB-INF/lib` without the context listener installed is unsupported and will not work correctly.
|
|
||||||
|
|
||||||
The context listener has no dependencies to the TwelveMonkeys ImageIO plugins, and may be used with JAI ImageIO
|
|
||||||
or other ImageIO plugins as well.
|
|
||||||
|
|
||||||
Another safe option, is to place the JAR files in the application server's shared or common lib folder.
|
|
||||||
|
|
||||||
#### Using the ResampleOp
|
#### Using the ResampleOp
|
||||||
|
|
||||||
@@ -411,15 +190,15 @@ The library comes with a resampling (image resizing) operation, that contains ma
|
|||||||
to provide excellent results at reasonable speed.
|
to provide excellent results at reasonable speed.
|
||||||
|
|
||||||
```java
|
```java
|
||||||
import com.twelvemonkeys.image.ResampleOp;
|
import com.twelvemonkeys.image.ResampleOp;
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
BufferedImage input = ...; // Image to resample
|
BufferedImage input = ...; // Image to resample
|
||||||
int width, height = ...; // new width/height
|
int width, height = ...; // new width/height
|
||||||
|
|
||||||
BufferedImageOp resampler = new ResampleOp(width, height, ResampleOp.FILTER_LANCZOS); // A good default filter, see class documentation for more info
|
BufferedImageOp resampler = new ResampleOp(width, height, ResampleOp.FILTER_LANCZOS); // A good default filter, see class documentation for more info
|
||||||
BufferedImage output = resampler.filter(input, null);
|
BufferedImage output = resampler.filter(input, null);
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Using the DiffusionDither
|
#### Using the DiffusionDither
|
||||||
@@ -428,14 +207,14 @@ The library comes with a dithering operation, that can be used to convert `Buffe
|
|||||||
Floyd-Steinberg error-diffusion dither.
|
Floyd-Steinberg error-diffusion dither.
|
||||||
|
|
||||||
```java
|
```java
|
||||||
import com.twelvemonkeys.image.DiffusionDither;
|
import com.twelvemonkeys.image.DiffusionDither;
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
BufferedImage input = ...; // Image to dither
|
BufferedImage input = ...; // Image to dither
|
||||||
|
|
||||||
BufferedImageOp ditherer = new DiffusionDither();
|
BufferedImageOp ditherer = new DiffusionDither();
|
||||||
BufferedImage output = ditherer.filter(input, null);
|
BufferedImage output = ditherer.filter(input, null);
|
||||||
```
|
```
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
@@ -451,7 +230,7 @@ Build the project (using [Maven](http://maven.apache.org/download.cgi)):
|
|||||||
|
|
||||||
$ mvn package
|
$ mvn package
|
||||||
|
|
||||||
Currently, the recommended JDK for making a build is Oracle JDK 7.x or 8.x.
|
Currently, the recommended JDK for making a build is Oracle JDK 8.x.
|
||||||
|
|
||||||
It's possible to build using OpenJDK, but some tests might fail due to some minor differences between the color management systems used. You will need to either disable the tests in question, or build without tests altogether.
|
It's possible to build using OpenJDK, but some tests might fail due to some minor differences between the color management systems used. You will need to either disable the tests in question, or build without tests altogether.
|
||||||
|
|
||||||
@@ -473,10 +252,10 @@ The ImageIO registry and service lookup mechanism will make sure the plugins are
|
|||||||
To verify that the JPEG plugin is installed and used at run-time, you could use the following code:
|
To verify that the JPEG plugin is installed and used at run-time, you could use the following code:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("JPEG");
|
Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("JPEG");
|
||||||
while (readers.hasNext()) {
|
while (readers.hasNext()) {
|
||||||
System.out.println("reader: " + readers.next());
|
System.out.println("reader: " + readers.next());
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The first line should print:
|
The first line should print:
|
||||||
@@ -488,82 +267,144 @@ The first line should print:
|
|||||||
To depend on the JPEG and TIFF plugin using Maven, add the following to your POM:
|
To depend on the JPEG and TIFF plugin using Maven, add the following to your POM:
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
|
...
|
||||||
|
<dependencies>
|
||||||
...
|
...
|
||||||
<dependencies>
|
<dependency>
|
||||||
...
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<dependency>
|
<artifactId>imageio-jpeg</artifactId>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<version>3.6.3</version>
|
||||||
<artifactId>imageio-jpeg</artifactId>
|
</dependency>
|
||||||
<version>3.4.3</version>
|
<dependency>
|
||||||
</dependency>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<dependency>
|
<artifactId>imageio-tiff</artifactId>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<version>3.6.3</version>
|
||||||
<artifactId>imageio-tiff</artifactId>
|
</dependency>
|
||||||
<version>3.4.3</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Optional dependency. Needed only if you deploy `ImageIO` plugins as part of a web app.
|
Optional dependency. Needed only if you deploy ImageIO plugins as part of a web app.
|
||||||
Make sure you add the `IIOProviderContextListener` to your `web.xml`, see above.
|
Make sure you add the IIOProviderContextListener to your web.xml, see above.
|
||||||
-->
|
-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.servlet</groupId>
|
<groupId>com.twelvemonkeys.servlet</groupId>
|
||||||
<artifactId>servlet</artifactId>
|
<artifactId>servlet</artifactId>
|
||||||
<version>3.4.3</version>
|
<version>3.6.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Manual dependency example
|
#### Manual dependency example
|
||||||
|
|
||||||
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.4.3.jar
|
twelvemonkeys-common-lang-3.6.3.jar
|
||||||
twelvemonkeys-common-io-3.4.3.jar
|
twelvemonkeys-common-io-3.6.3.jar
|
||||||
twelvemonkeys-common-image-3.4.3.jar
|
twelvemonkeys-common-image-3.6.3.jar
|
||||||
twelvemonkeys-imageio-core-3.4.3.jar
|
twelvemonkeys-imageio-core-3.6.3.jar
|
||||||
twelvemonkeys-imageio-metadata-3.4.3.jar
|
twelvemonkeys-imageio-metadata-3.6.3.jar
|
||||||
twelvemonkeys-imageio-jpeg-3.4.3.jar
|
twelvemonkeys-imageio-jpeg-3.6.3.jar
|
||||||
twelvemonkeys-imageio-tiff-3.4.3.jar
|
twelvemonkeys-imageio-tiff-3.6.3.jar
|
||||||
|
|
||||||
|
#### Deploying the plugins in a web app
|
||||||
|
|
||||||
|
Because the `ImageIO` plugin registry (the `IIORegistry`) is "VM global", it doesn't by default work well with
|
||||||
|
servlet contexts. This is especially evident if you load plugins from the `WEB-INF/lib` or `classes` folder.
|
||||||
|
Unless you add `ImageIO.scanForPlugins()` somewhere in your code, the plugins might never be available at all.
|
||||||
|
|
||||||
|
In addition, servlet contexts dynamically loads and unloads classes (using a new class loader per context).
|
||||||
|
If you restart your application, old classes will by default remain in memory forever (because the next time
|
||||||
|
`scanForPlugins` is called, it's another `ClassLoader` that scans/loads classes, and thus they will be new instances
|
||||||
|
in the registry). If a read is attempted using one of the remaining "old" readers, weird exceptions
|
||||||
|
(like `NullPointerException`s when accessing `static final` initialized fields or `NoClassDefFoundError`s
|
||||||
|
for uninitialized inner classes) may occur.
|
||||||
|
|
||||||
|
To work around both the discovery problem and the resource leak,
|
||||||
|
it is *strongly recommended* to use the `IIOProviderContextListener` that implements
|
||||||
|
dynamic loading and unloading of ImageIO plugins for web applications.
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<web-app ...>
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
<listener>
|
||||||
|
<display-name>ImageIO service provider loader/unloader</display-name>
|
||||||
|
<listener-class>com.twelvemonkeys.servlet.image.IIOProviderContextListener</listener-class>
|
||||||
|
</listener>
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
</web-app>
|
||||||
|
```
|
||||||
|
|
||||||
|
Loading plugins from `WEB-INF/lib` without the context listener installed is unsupported and will not work correctly.
|
||||||
|
|
||||||
|
The context listener has no dependencies to the TwelveMonkeys ImageIO plugins, and may be used with JAI ImageIO
|
||||||
|
or other ImageIO plugins as well.
|
||||||
|
|
||||||
|
Another safe option, is to place the JAR files in the application server's shared or common lib folder.
|
||||||
|
|
||||||
|
#### Including the plugins in a "fat" JAR
|
||||||
|
|
||||||
|
The recommended way to use the plugins, is just to include the JARs as-is in your project, through a Maven dependency or similar.
|
||||||
|
Re-packaging is not necessary to use the library, and not recommended.
|
||||||
|
|
||||||
|
However, if you like to create a "fat"
|
||||||
|
JAR, or otherwise like to re-package the JARs for some reason, it's important to remember that automatic discovery of
|
||||||
|
the plugins by ImageIO depends on the
|
||||||
|
[Service Provider Interface (SPI)](https://docs.oracle.com/javase/tutorial/sound/SPI-intro.html) mechanism.
|
||||||
|
In short, each JAR contains a special folder, named `META-INF/services` containing one or more files,
|
||||||
|
typically `javax.imageio.spi.ImageReaderSpi` and `javax.imageio.spi.ImageWriterSpi`.
|
||||||
|
These files exist *with the same name in every JAR*,
|
||||||
|
so if you simply unpack everything to a single folder or create a JAR, files will be overwritten and behavior be
|
||||||
|
unspecified (most likely you will end up with a single plugin being installed).
|
||||||
|
|
||||||
|
The solution is to make sure all files with the same name, are merged to a single file,
|
||||||
|
containing all the SPI information of each type. If using the Maven Shade plugin, you should use the
|
||||||
|
[ServicesResourceTransformer](https://maven.apache.org/plugins/maven-shade-plugin/examples/resource-transformers.html#ServicesResourceTransformer)
|
||||||
|
to properly merge these files. You may also want to use the
|
||||||
|
[ManifestResourceTransforme](https://maven.apache.org/plugins/maven-shade-plugin/examples/resource-transformers.html#ManifestResourceTransformer)
|
||||||
|
to get the correct vendor name, version info etc.
|
||||||
|
Other "fat" JAR bundlers will probably have similar mechanisms to merge entries with the same name.
|
||||||
|
|
||||||
### Links to prebuilt binaries
|
### Links to prebuilt binaries
|
||||||
|
|
||||||
##### Latest version (3.4.3)
|
##### Latest version (3.6.3)
|
||||||
|
|
||||||
Requires Java 7 or later.
|
Requires Java 7 or later.
|
||||||
|
|
||||||
Common dependencies
|
Common dependencies
|
||||||
* [common-lang-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-lang/3.4.3/common-lang-3.4.3.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.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-io/3.4.3/common-io-3.4.3.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.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-image/3.4.3/common-image-3.4.3.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.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-core/3.4.3/imageio-core-3.4.3.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.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-metadata/3.4.3/imageio-metadata-3.4.3.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.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-bmp/3.4.3/imageio-bmp-3.4.3.jar)
|
* [imageio-bmp-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-bmp/3.6.3/imageio-bmp-3.6.3.jar)
|
||||||
* [imageio-jpeg-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jpeg/3.4.3/imageio-jpeg-3.4.3.jar)
|
* [imageio-hdr-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-hdr/3.6.3/imageio-hdr-3.6.3.jar)
|
||||||
* [imageio-tiff-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tiff/3.4.3/imageio-tiff-3.4.3.jar)
|
* [imageio-icns-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-icns/3.6.3/imageio-icns-3.6.3.jar)
|
||||||
* [imageio-pnm-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pnm/3.4.3/imageio-pnm-3.4.3.jar)
|
* [imageio-iff-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-iff/3.6.3/imageio-iff-3.6.3.jar)
|
||||||
* [imageio-psd-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-psd/3.4.3/imageio-psd-3.4.3.jar)
|
* [imageio-jpeg-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jpeg/3.6.3/imageio-jpeg-3.6.3.jar)
|
||||||
* [imageio-hdr-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-hdr/3.4.3/imageio-hdr-3.4.3.jar)
|
* [imageio-pcx-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pcx/3.6.3/imageio-pcx-3.6.3.jar)
|
||||||
* [imageio-iff-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-iff/3.4.3/imageio-iff-3.4.3.jar)
|
* [imageio-pict-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pict/3.6.3/imageio-pict-3.6.3.jar)
|
||||||
* [imageio-pcx-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pcx/3.4.3/imageio-pcx-3.4.3.jar)
|
* [imageio-pnm-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pnm/3.6.3/imageio-pnm-3.6.3.jar)
|
||||||
* [imageio-pict-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pict/3.4.3/imageio-pict-3.4.3.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.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-sgi/3.4.3/imageio-sgi-3.4.3.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.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tga/3.4.3/imageio-tga-3.4.3.jar)
|
* [imageio-tga-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tga/3.6.3/imageio-tga-3.6.3.jar)
|
||||||
* [imageio-icns-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-icns/3.4.3/imageio-icns-3.4.3.jar)
|
* [imageio-thumbsdb-3.6.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-thumbsdb/3.6.3/imageio-thumbsdb-3.6.3.jar)
|
||||||
* [imageio-thumbsdb-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-thumbsdb/3.4.3/imageio-thumbsdb-3.4.3.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.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-batik/3.4.3/imageio-batik-3.4.3.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.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-clippath/3.4.3/imageio-clippath-3.4.3.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.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/servlet/servlet/3.4.3/servlet-3.4.3.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)
|
||||||
|
|
||||||
@@ -598,9 +439,9 @@ Servlet support
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
The project is distributed under the OSI approved [BSD license](http://opensource.org/licenses/BSD-3-Clause):
|
This project is provided under the OSI approved [BSD license](http://opensource.org/licenses/BSD-3-Clause):
|
||||||
|
|
||||||
Copyright (c) 2008-2018, Harald Kuhr
|
Copyright (c) 2008-2020, 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
|
||||||
@@ -661,10 +502,15 @@ the Sun/Oracle provided `JPEGImageReader` and `BMPImageReader`, and the Apple pr
|
|||||||
respectively. Using the pairwise ordering will not remove any functionality form these implementations, but in most
|
respectively. Using the pairwise ordering will not remove any functionality form these implementations, but in most
|
||||||
cases you'll end up using the TwelveMonkeys plug-ins instead.
|
cases you'll end up using the TwelveMonkeys plug-ins instead.
|
||||||
|
|
||||||
|
q: Why is there no support for common formats like GIF or PNG?
|
||||||
|
|
||||||
|
a: The short answer is simply that the built-in support in ImageIO for these formats are good enough as-is.
|
||||||
|
If you are looking for better PNG write performance on Java 7 and 8, see [JDK9 PNG Writer Backport](https://github.com/gredler/jdk9-png-writer-backport).
|
||||||
|
|
||||||
|
|
||||||
q: What about JAI? Several of the formats are already supported by JAI.
|
q: What about JAI? Several of the formats are already supported by JAI.
|
||||||
|
|
||||||
a: While JAI (and jai-imageio in particular) have support for some of the formats, JAI has some major issues.
|
a: While JAI (and jai-imageio in particular) have support for some of the same formats, JAI has some major issues.
|
||||||
The most obvious being:
|
The most obvious being:
|
||||||
- It's not actively developed. No issues has been fixed for years.
|
- It's not actively developed. No issues has been fixed for years.
|
||||||
- To get full format support, you need native libs.
|
- To get full format support, you need native libs.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys</groupId>
|
<groupId>com.twelvemonkeys</groupId>
|
||||||
<artifactId>twelvemonkeys</artifactId>
|
<artifactId>twelvemonkeys</artifactId>
|
||||||
<version>3.5</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<groupId>com.twelvemonkeys.bom</groupId>
|
<groupId>com.twelvemonkeys.bom</groupId>
|
||||||
@@ -123,6 +123,11 @@
|
|||||||
<artifactId>imageio-tiff</artifactId>
|
<artifactId>imageio-tiff</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
<artifactId>imageio-xwd</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- ImageIO 3rd party dependent plugins -->
|
<!-- ImageIO 3rd party dependent plugins -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.common</groupId>
|
<groupId>com.twelvemonkeys.common</groupId>
|
||||||
<artifactId>common</artifactId>
|
<artifactId>common</artifactId>
|
||||||
<version>3.5</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>common-image</artifactId>
|
<artifactId>common-image</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.common</groupId>
|
<groupId>com.twelvemonkeys.common</groupId>
|
||||||
<artifactId>common</artifactId>
|
<artifactId>common</artifactId>
|
||||||
<version>3.5</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>common-io</artifactId>
|
<artifactId>common-io</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ public final class FastByteArrayOutputStream extends ByteArrayOutputStream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(byte pBytes[], int pOffset, int pLength) {
|
public void write(byte[] pBytes, int pOffset, int pLength) {
|
||||||
if ((pOffset < 0) || (pOffset > pBytes.length) || (pLength < 0) ||
|
if ((pOffset < 0) || (pOffset > pBytes.length) || (pLength < 0) ||
|
||||||
((pOffset + pLength) > pBytes.length) || ((pOffset + pLength) < 0)) {
|
((pOffset + pLength) > pBytes.length) || ((pOffset + pLength) < 0)) {
|
||||||
throw new IndexOutOfBoundsException();
|
throw new IndexOutOfBoundsException();
|
||||||
@@ -98,7 +98,7 @@ public final class FastByteArrayOutputStream extends ByteArrayOutputStream {
|
|||||||
private void growIfNeeded(int pNewCount) {
|
private void growIfNeeded(int pNewCount) {
|
||||||
if (pNewCount > buf.length) {
|
if (pNewCount > buf.length) {
|
||||||
int newSize = Math.max(Math.min(buf.length << 1, buf.length + maxGrowSize), pNewCount);
|
int newSize = Math.max(Math.min(buf.length << 1, buf.length + maxGrowSize), pNewCount);
|
||||||
byte newBuf[] = new byte[newSize];
|
byte[] newBuf = new byte[newSize];
|
||||||
System.arraycopy(buf, 0, newBuf, 0, count);
|
System.arraycopy(buf, 0, newBuf, 0, count);
|
||||||
buf = newBuf;
|
buf = newBuf;
|
||||||
}
|
}
|
||||||
@@ -113,7 +113,7 @@ public final class FastByteArrayOutputStream extends ByteArrayOutputStream {
|
|||||||
// Non-synchronized version of toByteArray
|
// Non-synchronized version of toByteArray
|
||||||
@Override
|
@Override
|
||||||
public byte[] toByteArray() {
|
public byte[] toByteArray() {
|
||||||
byte newBuf[] = new byte[count];
|
byte[] newBuf = new byte[count];
|
||||||
System.arraycopy(buf, 0, newBuf, 0, count);
|
System.arraycopy(buf, 0, newBuf, 0, count);
|
||||||
|
|
||||||
return newBuf;
|
return newBuf;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.common</groupId>
|
<groupId>com.twelvemonkeys.common</groupId>
|
||||||
<artifactId>common</artifactId>
|
<artifactId>common</artifactId>
|
||||||
<version>3.5</version>
|
<version>3.6.5-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>common-lang</artifactId>
|
<artifactId>common-lang</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|||||||
@@ -129,8 +129,7 @@ public class Time {
|
|||||||
* @see #toString(String)
|
* @see #toString(String)
|
||||||
*/
|
*/
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "" + getMinutes() + ":"
|
return getMinutes() + ":" + (getSeconds() < 10 ? "0" : "") + getSeconds();
|
||||||
+ (getSeconds() < 10 ? "0" : "") + getSeconds();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -44,12 +44,12 @@ import java.util.Vector;
|
|||||||
* The format is expressed in a string as follows:
|
* The format is expressed in a string as follows:
|
||||||
* <DL>
|
* <DL>
|
||||||
* <DD>m (or any multiple of m's)
|
* <DD>m (or any multiple of m's)
|
||||||
* <DT>the minutes part (padded with 0's, if number has less digits than
|
* <DT>the minutes part (padded with 0's, if number has less digits than
|
||||||
* the number of m's)
|
* the number of m's)
|
||||||
* m -> 0,1,...,59,60,61,...
|
* m -> 0,1,...,59,60,61,...
|
||||||
* mm -> 00,01,...,59,60,61,...
|
* mm -> 00,01,...,59,60,61,...
|
||||||
* <DD>s or ss
|
* <DD>s or ss
|
||||||
* <DT>the seconds part (padded with 0's, if number has less digits than
|
* <DT>the seconds part (padded with 0's, if number has less digits than
|
||||||
* the number of s's)
|
* the number of s's)
|
||||||
* s -> 0,1,...,59
|
* s -> 0,1,...,59
|
||||||
* ss -> 00,01,...,59
|
* ss -> 00,01,...,59
|
||||||
@@ -62,7 +62,7 @@ import java.util.Vector;
|
|||||||
* <P>
|
* <P>
|
||||||
* Known bugs:
|
* Known bugs:
|
||||||
* <P>
|
* <P>
|
||||||
* The last character in the formatString is not escaped, while it should be.
|
* The last character in the formatString is not escaped, while it should be.
|
||||||
* The first character after an escaped character is escaped while is shouldn't
|
* The first character after an escaped character is escaped while is shouldn't
|
||||||
* be.
|
* be.
|
||||||
* <P>
|
* <P>
|
||||||
@@ -81,15 +81,15 @@ public class TimeFormat extends Format {
|
|||||||
final static String SECOND = "s";
|
final static String SECOND = "s";
|
||||||
final static String TIME = "S";
|
final static String TIME = "S";
|
||||||
final static String ESCAPE = "\\";
|
final static String ESCAPE = "\\";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The default time format
|
* The default time format
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private final static TimeFormat DEFAULT_FORMAT = new TimeFormat("m:ss");
|
private final static TimeFormat DEFAULT_FORMAT = new TimeFormat("m:ss");
|
||||||
protected String formatString = null;
|
protected String formatString = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main method for testing ONLY
|
* Main method for testing ONLY
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@ public class TimeFormat extends Format {
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
time = new Time();
|
time = new Time();
|
||||||
|
|
||||||
System.out.println("Time is \"" + out.format(time) +
|
System.out.println("Time is \"" + out.format(time) +
|
||||||
"\" according to format \"" + out.formatString + "\"");
|
"\" according to format \"" + out.formatString + "\"");
|
||||||
}
|
}
|
||||||
@@ -147,18 +147,18 @@ public class TimeFormat extends Format {
|
|||||||
String previous = null;
|
String previous = null;
|
||||||
String current = null;
|
String current = null;
|
||||||
int previousCount = 0;
|
int previousCount = 0;
|
||||||
|
|
||||||
while (tok.hasMoreElements()) {
|
while (tok.hasMoreElements()) {
|
||||||
current = tok.nextToken();
|
current = tok.nextToken();
|
||||||
|
|
||||||
if (previous != null && previous.equals(ESCAPE)) {
|
if (previous != null && previous.equals(ESCAPE)) {
|
||||||
// Handle escaping of s, S or m
|
// Handle escaping of s, S or m
|
||||||
current = ((current != null) ? current : "")
|
current = ((current != null) ? current : "")
|
||||||
+ (tok.hasMoreElements() ? tok.nextToken() : "");
|
+ (tok.hasMoreElements() ? tok.nextToken() : "");
|
||||||
previous = null;
|
previous = null;
|
||||||
previousCount = 0;
|
previousCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip over first,
|
// Skip over first,
|
||||||
// or if current is the same, increase count, and try again
|
// or if current is the same, increase count, and try again
|
||||||
if (previous == null || previous.equals(current)) {
|
if (previous == null || previous.equals(current)) {
|
||||||
@@ -173,12 +173,12 @@ public class TimeFormat extends Format {
|
|||||||
formatter.add(new SecondsFormatter(previousCount));
|
formatter.add(new SecondsFormatter(previousCount));
|
||||||
else if (previous.equals(TIME))
|
else if (previous.equals(TIME))
|
||||||
formatter.add(new SecondsFormatter(-1));
|
formatter.add(new SecondsFormatter(-1));
|
||||||
else
|
else
|
||||||
formatter.add(new TextFormatter(previous));
|
formatter.add(new TextFormatter(previous));
|
||||||
|
|
||||||
previousCount = 1;
|
previousCount = 1;
|
||||||
previous = current;
|
previous = current;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,7 +197,7 @@ public class TimeFormat extends Format {
|
|||||||
// Debug
|
// Debug
|
||||||
/*
|
/*
|
||||||
for (int i = 0; i < formatter.size(); i++) {
|
for (int i = 0; i < formatter.size(); i++) {
|
||||||
System.out.println("Formatter " + formatter.get(i).getClass()
|
System.out.println("Formatter " + formatter.get(i).getClass()
|
||||||
+ ": length=" + ((TimeFormatter) formatter.get(i)).digits);
|
+ ": length=" + ((TimeFormatter) formatter.get(i)).digits);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@@ -206,7 +206,7 @@ public class TimeFormat extends Format {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DUMMY IMPLEMENTATION!!
|
* DUMMY IMPLEMENTATION!!
|
||||||
* Not locale specific.
|
* Not locale specific.
|
||||||
*/
|
*/
|
||||||
@@ -259,9 +259,9 @@ public class TimeFormat extends Format {
|
|||||||
/** DUMMY IMPLEMENTATION!! */
|
/** DUMMY IMPLEMENTATION!! */
|
||||||
public Object parseObject(String pStr, ParsePosition pStatus) {
|
public Object parseObject(String pStr, ParsePosition pStatus) {
|
||||||
Time t = parse(pStr);
|
Time t = parse(pStr);
|
||||||
|
|
||||||
pStatus.setIndex(pStr.length()); // Not 100%
|
pStatus.setIndex(pStr.length()); // Not 100%
|
||||||
|
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,7 +270,7 @@ public class TimeFormat extends Format {
|
|||||||
* <p>
|
* <p>
|
||||||
* Will bug on some formats. It's safest to always use delimiters between
|
* Will bug on some formats. It's safest to always use delimiters between
|
||||||
* the minutes (m) and seconds (s) part.
|
* the minutes (m) and seconds (s) part.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public Time parse(String pStr) {
|
public Time parse(String pStr) {
|
||||||
Time time = new Time();
|
Time time = new Time();
|
||||||
@@ -286,7 +286,7 @@ public class TimeFormat extends Format {
|
|||||||
&& (pos + skip < pStr.length()) ; i++) {
|
&& (pos + skip < pStr.length()) ; i++) {
|
||||||
// Go to next offset
|
// Go to next offset
|
||||||
pos += skip;
|
pos += skip;
|
||||||
|
|
||||||
if (formatter[i] instanceof MinutesFormatter) {
|
if (formatter[i] instanceof MinutesFormatter) {
|
||||||
// Parse MINUTES
|
// Parse MINUTES
|
||||||
if ((i + 1) < formatter.length
|
if ((i + 1) < formatter.length
|
||||||
@@ -327,9 +327,9 @@ public class TimeFormat extends Format {
|
|||||||
else {
|
else {
|
||||||
// Cannot possibly know how long?
|
// Cannot possibly know how long?
|
||||||
skip = 0;
|
skip = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get seconds
|
// Get seconds
|
||||||
sec = Integer.parseInt(pStr.substring(pos, skip));
|
sec = Integer.parseInt(pStr.substring(pos, skip));
|
||||||
// System.out.println("Only seconds: " + sec);
|
// System.out.println("Only seconds: " + sec);
|
||||||
@@ -343,7 +343,7 @@ public class TimeFormat extends Format {
|
|||||||
&& formatter[i + 1] instanceof TextFormatter) {
|
&& formatter[i + 1] instanceof TextFormatter) {
|
||||||
// Skip until next format element
|
// Skip until next format element
|
||||||
skip = pStr.indexOf(((TextFormatter) formatter[i + 1]).text, pos);
|
skip = pStr.indexOf(((TextFormatter) formatter[i + 1]).text, pos);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if ((i + 1) >= formatter.length) {
|
else if ((i + 1) >= formatter.length) {
|
||||||
// Skip until end of string
|
// Skip until end of string
|
||||||
@@ -359,7 +359,7 @@ public class TimeFormat extends Format {
|
|||||||
else if (formatter[i] instanceof TextFormatter) {
|
else if (formatter[i] instanceof TextFormatter) {
|
||||||
skip = formatter[i].digits;
|
skip = formatter[i].digits;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the minutes part if we should
|
// Set the minutes part if we should
|
||||||
@@ -390,7 +390,7 @@ class SecondsFormatter extends TimeFormatter {
|
|||||||
SecondsFormatter(int pDigits) {
|
SecondsFormatter(int pDigits) {
|
||||||
digits = pDigits;
|
digits = pDigits;
|
||||||
}
|
}
|
||||||
|
|
||||||
String format(Time t) {
|
String format(Time t) {
|
||||||
// Negative number of digits, means all seconds, no padding
|
// Negative number of digits, means all seconds, no padding
|
||||||
if (digits < 0) {
|
if (digits < 0) {
|
||||||
@@ -404,7 +404,7 @@ class SecondsFormatter extends TimeFormatter {
|
|||||||
|
|
||||||
// Else return it with leading 0's
|
// Else return it with leading 0's
|
||||||
//return StringUtil.formatNumber(t.getSeconds(), digits);
|
//return StringUtil.formatNumber(t.getSeconds(), digits);
|
||||||
return StringUtil.pad("" + t.getSeconds(), digits, "0", true);
|
return StringUtil.pad(String.valueOf(t.getSeconds()), digits, "0", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,7 +425,7 @@ class MinutesFormatter extends TimeFormatter {
|
|||||||
|
|
||||||
// Else return it with leading 0's
|
// Else return it with leading 0's
|
||||||
//return StringUtil.formatNumber(t.getMinutes(), digits);
|
//return StringUtil.formatNumber(t.getMinutes(), digits);
|
||||||
return StringUtil.pad("" + t.getMinutes(), digits, "0", true);
|
return StringUtil.pad(String.valueOf(t.getMinutes()), digits, "0", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1117,18 +1117,19 @@ public abstract class CollectionAbstractTest extends ObjectAbstractTest {
|
|||||||
/**
|
/**
|
||||||
* Tests {@link Collection#toArray(Object[])}.
|
* Tests {@link Collection#toArray(Object[])}.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings({"SuspiciousToArrayCall", "RedundantCast"})
|
||||||
@Test
|
@Test
|
||||||
public void testCollectionToArray2() {
|
public void testCollectionToArray2() {
|
||||||
resetEmpty();
|
resetEmpty();
|
||||||
Object[] a = new Object[] { new Object(), null, null };
|
Object[] a = new Object[] { new Object(), null, null };
|
||||||
Object[] array = collection.toArray(a);
|
Object[] array = collection.toArray(a);
|
||||||
assertArrayEquals("Given array shouldn't shrink", array, a);
|
assertArrayEquals("Given array shouldn't shrink", array, a);
|
||||||
assertEquals("Last element should be set to null", a[0], null);
|
assertNull("Last element should be set to null", a[0]);
|
||||||
verifyAll();
|
verifyAll();
|
||||||
|
|
||||||
resetFull();
|
resetFull();
|
||||||
try {
|
try {
|
||||||
array = collection.toArray(new Void[0]);
|
collection.toArray(new Void[0]);
|
||||||
fail("toArray(new Void[0]) should raise ArrayStore");
|
fail("toArray(new Void[0]) should raise ArrayStore");
|
||||||
} catch (ArrayStoreException e) {
|
} catch (ArrayStoreException e) {
|
||||||
// expected
|
// expected
|
||||||
@@ -1136,7 +1137,7 @@ public abstract class CollectionAbstractTest extends ObjectAbstractTest {
|
|||||||
verifyAll();
|
verifyAll();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
array = collection.toArray(null);
|
collection.toArray((Object[]) null);
|
||||||
fail("toArray(null) should raise NPE");
|
fail("toArray(null) should raise NPE");
|
||||||
} catch (NullPointerException e) {
|
} catch (NullPointerException e) {
|
||||||
// expected
|
// expected
|
||||||
@@ -1150,13 +1151,13 @@ public abstract class CollectionAbstractTest extends ObjectAbstractTest {
|
|||||||
|
|
||||||
// Figure out if they're all the same class
|
// Figure out if they're all the same class
|
||||||
// TODO: It'd be nicer to detect a common superclass
|
// TODO: It'd be nicer to detect a common superclass
|
||||||
HashSet classes = new HashSet();
|
HashSet<Class<?>> classes = new HashSet<>();
|
||||||
for (int i = 0; i < array.length; i++) {
|
for (int i = 0; i < array.length; i++) {
|
||||||
classes.add((array[i] == null) ? null : array[i].getClass());
|
classes.add((array[i] == null) ? null : array[i].getClass());
|
||||||
}
|
}
|
||||||
if (classes.size() > 1) return;
|
if (classes.size() > 1) return;
|
||||||
|
|
||||||
Class cl = (Class)classes.iterator().next();
|
Class<?> cl = (Class<?>)classes.iterator().next();
|
||||||
if (Map.Entry.class.isAssignableFrom(cl)) { // check needed for protective cases like Predicated/Unmod map entrySet
|
if (Map.Entry.class.isAssignableFrom(cl)) { // check needed for protective cases like Predicated/Unmod map entrySet
|
||||||
cl = Map.Entry.class;
|
cl = Map.Entry.class;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -250,12 +250,12 @@ public class CollectionUtilTest {
|
|||||||
assertCorrectListIterator(new ArrayList<String>(Arrays.asList(new String[] {"foo", "bar", "baz", "boo"})).subList(1, 3).listIterator(0), new String[] {"bar", "baz"}, true, true);
|
assertCorrectListIterator(new ArrayList<String>(Arrays.asList(new String[] {"foo", "bar", "baz", "boo"})).subList(1, 3).listIterator(0), new String[] {"bar", "baz"}, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertCorrectListIterator(ListIterator<String> iterator, final Object[] elements) {
|
private static void assertCorrectListIterator(ListIterator<String> iterator, final Object[] elements) {
|
||||||
assertCorrectListIterator(iterator, elements, false, false);
|
assertCorrectListIterator(iterator, elements, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: The test is can only test list iterators with a starting index == 0
|
// NOTE: The test is can only test list iterators with a starting index == 0
|
||||||
private void assertCorrectListIterator(ListIterator<String> iterator, final Object[] elements, boolean skipRemove, boolean skipAdd) {
|
private static void assertCorrectListIterator(ListIterator<String> iterator, final Object[] elements, boolean skipRemove, boolean skipAdd) {
|
||||||
// Index is now "before 0"
|
// Index is now "before 0"
|
||||||
assertEquals(-1, iterator.previousIndex());
|
assertEquals(-1, iterator.previousIndex());
|
||||||
assertEquals(0, iterator.nextIndex());
|
assertEquals(0, iterator.nextIndex());
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys</groupId>
|
<groupId>com.twelvemonkeys</groupId>
|
||||||
<artifactId>twelvemonkeys</artifactId>
|
<artifactId>twelvemonkeys</artifactId>
|
||||||
<version>3.5</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>
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<version>4.7</version>
|
<version>4.13.1</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys</groupId>
|
<groupId>com.twelvemonkeys</groupId>
|
||||||
<artifactId>twelvemonkeys</artifactId>
|
<artifactId>twelvemonkeys</artifactId>
|
||||||
<version>3.5</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>
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit</artifactId>
|
||||||
<version>4.7</version>
|
<version>4.13.1</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|||||||
@@ -0,0 +1,158 @@
|
|||||||
|
package com.twelvemonkeys.contrib.exif;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.image.ImageUtil;
|
||||||
|
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||||
|
|
||||||
|
import org.w3c.dom.NodeList;
|
||||||
|
|
||||||
|
import javax.imageio.IIOImage;
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.imageio.ImageReader;
|
||||||
|
import javax.imageio.metadata.IIOMetadata;
|
||||||
|
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
||||||
|
import javax.imageio.metadata.IIOMetadataNode;
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import static com.twelvemonkeys.contrib.tiff.TIFFUtilities.applyOrientation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EXIFUtilities.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @version : EXIFUtilities.java,v 1.0 23/06/2020
|
||||||
|
*/
|
||||||
|
public class EXIFUtilities {
|
||||||
|
/**
|
||||||
|
* Reads image and metadata, applies Exif orientation to image, and returns everything as an {@code IIOImage}.
|
||||||
|
*
|
||||||
|
* @param input a {@code URL}
|
||||||
|
* @return an {@code IIOImage} containing the correctly oriented image and metadata including rotation info.
|
||||||
|
* @throws IOException if an error occurs during reading.
|
||||||
|
*/
|
||||||
|
public static IIOImage readWithOrientation(final URL input) throws IOException {
|
||||||
|
try (ImageInputStream stream = ImageIO.createImageInputStream(input)) {
|
||||||
|
return readWithOrientation(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads image and metadata, applies Exif orientation to image, and returns everything as an {@code IIOImage}.
|
||||||
|
*
|
||||||
|
* @param input an {@code InputStream}
|
||||||
|
* @return an {@code IIOImage} containing the correctly oriented image and metadata including rotation info.
|
||||||
|
* @throws IOException if an error occurs during reading.
|
||||||
|
*/
|
||||||
|
public static IIOImage readWithOrientation(final InputStream input) throws IOException {
|
||||||
|
try (ImageInputStream stream = ImageIO.createImageInputStream(input)) {
|
||||||
|
return readWithOrientation(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads image and metadata, applies Exif orientation to image, and returns everything as an {@code IIOImage}.
|
||||||
|
*
|
||||||
|
* @param input a {@code File}
|
||||||
|
* @return an {@code IIOImage} containing the correctly oriented image and metadata including rotation info.
|
||||||
|
* @throws IOException if an error occurs during reading.
|
||||||
|
*/
|
||||||
|
public static IIOImage readWithOrientation(final File input) throws IOException {
|
||||||
|
try (ImageInputStream stream = ImageIO.createImageInputStream(input)) {
|
||||||
|
return readWithOrientation(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads image and metadata, applies Exif orientation to image, and returns everything as an {@code IIOImage}.
|
||||||
|
*
|
||||||
|
* @param input an {@code ImageInputStream}
|
||||||
|
* @return an {@code IIOImage} containing the correctly oriented image and metadata including rotation info.
|
||||||
|
* @throws IOException if an error occurs during reading.
|
||||||
|
*/
|
||||||
|
public static IIOImage readWithOrientation(final ImageInputStream input) throws IOException {
|
||||||
|
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
|
||||||
|
if (!readers.hasNext()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageReader reader = readers.next();
|
||||||
|
try {
|
||||||
|
reader.setInput(input, true, false);
|
||||||
|
|
||||||
|
IIOMetadata metadata = reader.getImageMetadata(0);
|
||||||
|
BufferedImage bufferedImage = applyOrientation(reader.read(0), findImageOrientation(metadata).value());
|
||||||
|
|
||||||
|
return new IIOImage(bufferedImage, null, metadata);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
reader.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the {@code ImageOrientation} tag, if any, and returns an {@link Orientation} based on its
|
||||||
|
* {@code value} attribute.
|
||||||
|
* If no match is found or the tag is not present, {@code Normal} (the default orientation) is returned.
|
||||||
|
*
|
||||||
|
* @param metadata an {@code IIOMetadata} object
|
||||||
|
* @return the {@code Orientation} matching the {@code value} attribute of the {@code ImageOrientation} tag,
|
||||||
|
* or {@code Normal}, never {@code null}.
|
||||||
|
* @see Orientation
|
||||||
|
* @see <a href="https://docs.oracle.com/javase/7/docs/api/javax/imageio/metadata/doc-files/standard_metadata.html">Standard (Plug-in Neutral) Metadata Format Specification</a>
|
||||||
|
*/
|
||||||
|
public static Orientation findImageOrientation(final IIOMetadata metadata) {
|
||||||
|
if (metadata != null) {
|
||||||
|
IIOMetadataNode root = (IIOMetadataNode) metadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
|
||||||
|
NodeList imageOrientations = root.getElementsByTagName("ImageOrientation");
|
||||||
|
|
||||||
|
if (imageOrientations != null && imageOrientations.getLength() > 0) {
|
||||||
|
IIOMetadataNode imageOrientation = (IIOMetadataNode) imageOrientations.item(0);
|
||||||
|
return Orientation.fromMetadataOrientation(imageOrientation.getAttribute("value"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Orientation.Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws IOException {
|
||||||
|
for (String arg : args) {
|
||||||
|
File input = new File(arg);
|
||||||
|
|
||||||
|
// Read everything but thumbnails (similar to ImageReader.readAll(0, null)),
|
||||||
|
// and applies the correct image orientation
|
||||||
|
IIOImage image = readWithOrientation(input);
|
||||||
|
|
||||||
|
if (image == null) {
|
||||||
|
System.err.printf("No reader for %s%n", input);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finds the orientation as defined by the javax_imageio_1.0 format
|
||||||
|
Orientation orientation = findImageOrientation(image.getMetadata());
|
||||||
|
|
||||||
|
// Retrieve the image as a BufferedImage. The image is already rotated by the readWithOrientation method
|
||||||
|
// In this case it will already be a BufferedImage, so using a cast will also do
|
||||||
|
// (i.e.: BufferedImage bufferedImage = (BufferedImage) image.getRenderedImage())
|
||||||
|
BufferedImage bufferedImage = ImageUtil.toBuffered(image.getRenderedImage());
|
||||||
|
|
||||||
|
// Demo purpose only, show image with orientation details in title
|
||||||
|
DisplayHelper.showIt(bufferedImage, input.getName() + ": " + orientation.name() + "/" + orientation.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't do this... :-) Provided for convenience/demo only!
|
||||||
|
static abstract class DisplayHelper extends ImageReaderBase {
|
||||||
|
private DisplayHelper() {
|
||||||
|
super(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void showIt(BufferedImage image, String title) {
|
||||||
|
ImageReaderBase.showIt(image, title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package com.twelvemonkeys.contrib.exif;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.contrib.tiff.TIFFUtilities;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Orientation.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @version : Orientation.java,v 1.0 10/07/2020 harald.kuhr
|
||||||
|
*/
|
||||||
|
public enum Orientation {
|
||||||
|
Normal(TIFFUtilities.TIFFBaseline.ORIENTATION_TOPLEFT),
|
||||||
|
FlipH(TIFFUtilities.TIFFExtension.ORIENTATION_TOPRIGHT),
|
||||||
|
Rotate180(TIFFUtilities.TIFFExtension.ORIENTATION_BOTRIGHT),
|
||||||
|
FlipV(TIFFUtilities.TIFFExtension.ORIENTATION_BOTLEFT),
|
||||||
|
FlipVRotate90(TIFFUtilities.TIFFExtension.ORIENTATION_LEFTTOP),
|
||||||
|
Rotate270(TIFFUtilities.TIFFExtension.ORIENTATION_RIGHTTOP),
|
||||||
|
FlipHRotate90(TIFFUtilities.TIFFExtension.ORIENTATION_RIGHTBOT),
|
||||||
|
Rotate90(TIFFUtilities.TIFFExtension.ORIENTATION_LEFTBOT);
|
||||||
|
|
||||||
|
// name as defined in javax.imageio metadata
|
||||||
|
private final int value; // value as defined in TIFF spec
|
||||||
|
|
||||||
|
Orientation(int value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int value() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Orientation fromMetadataOrientation(final String orientationName) {
|
||||||
|
if (orientationName != null) {
|
||||||
|
try {
|
||||||
|
return valueOf(orientationName);
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException e) {
|
||||||
|
// Not found, try ignore case match, as some metadata implementations are known to return "normal" etc.
|
||||||
|
String lowerCaseName = orientationName.toLowerCase();
|
||||||
|
|
||||||
|
for (Orientation orientation : values()) {
|
||||||
|
if (orientation.name().toLowerCase().equals(lowerCaseName)) {
|
||||||
|
return orientation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Metadata does not have other orientations, default to Normal
|
||||||
|
return Normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Orientation fromTIFFOrientation(final int tiffOrientation) {
|
||||||
|
for (Orientation orientation : values()) {
|
||||||
|
if (orientation.value() == tiffOrientation) {
|
||||||
|
return orientation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No other TIFF orientations possible, default to Normal
|
||||||
|
return Normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -200,11 +200,10 @@ public final class TIFFUtilities {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static List<TIFFPage> getPages(ImageInputStream imageInput) throws IOException {
|
public static List<TIFFPage> getPages(ImageInputStream imageInput) throws IOException {
|
||||||
ArrayList<TIFFPage> pages = new ArrayList<TIFFPage>();
|
|
||||||
|
|
||||||
CompoundDirectory IFDs = (CompoundDirectory) new TIFFReader().read(imageInput);
|
CompoundDirectory IFDs = (CompoundDirectory) new TIFFReader().read(imageInput);
|
||||||
|
|
||||||
int pageCount = IFDs.directoryCount();
|
final int pageCount = IFDs.directoryCount();
|
||||||
|
List<TIFFPage> pages = new ArrayList<>(pageCount);
|
||||||
for (int pageIndex = 0; pageIndex < pageCount; pageIndex++) {
|
for (int pageIndex = 0; pageIndex < pageCount; pageIndex++) {
|
||||||
pages.add(new TIFFPage(IFDs.getDirectory(pageIndex), imageInput));
|
pages.add(new TIFFPage(IFDs.getDirectory(pageIndex), imageInput));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
package com.twelvemonkeys.contrib.exif;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static com.twelvemonkeys.contrib.exif.Orientation.*;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OrientationTest.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by : harald.kuhr$
|
||||||
|
* @version : OrientationTest.java,v 1.0 10/07/2020 harald.kuhr Exp$
|
||||||
|
*/
|
||||||
|
public class OrientationTest {
|
||||||
|
@Test
|
||||||
|
public void testFromMetadataOrientationNull() {
|
||||||
|
assertEquals(Normal, Orientation.fromMetadataOrientation(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromMetadataOrientation() {
|
||||||
|
assertEquals(Normal, Orientation.fromMetadataOrientation("Normal"));
|
||||||
|
assertEquals(Rotate90, Orientation.fromMetadataOrientation("Rotate90"));
|
||||||
|
assertEquals(Rotate180, Orientation.fromMetadataOrientation("Rotate180"));
|
||||||
|
assertEquals(Rotate270, Orientation.fromMetadataOrientation("Rotate270"));
|
||||||
|
assertEquals(FlipH, Orientation.fromMetadataOrientation("FlipH"));
|
||||||
|
assertEquals(FlipV, Orientation.fromMetadataOrientation("FlipV"));
|
||||||
|
assertEquals(FlipHRotate90, Orientation.fromMetadataOrientation("FlipHRotate90"));
|
||||||
|
assertEquals(FlipVRotate90, Orientation.fromMetadataOrientation("FlipVRotate90"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromMetadataOrientationIgnoreCase() {
|
||||||
|
assertEquals(Normal, Orientation.fromMetadataOrientation("normal"));
|
||||||
|
assertEquals(Rotate90, Orientation.fromMetadataOrientation("rotate90"));
|
||||||
|
assertEquals(Rotate180, Orientation.fromMetadataOrientation("ROTATE180"));
|
||||||
|
assertEquals(Rotate270, Orientation.fromMetadataOrientation("ROTATE270"));
|
||||||
|
assertEquals(FlipH, Orientation.fromMetadataOrientation("FLIPH"));
|
||||||
|
assertEquals(FlipV, Orientation.fromMetadataOrientation("flipv"));
|
||||||
|
assertEquals(FlipHRotate90, Orientation.fromMetadataOrientation("FLIPhrotate90"));
|
||||||
|
assertEquals(FlipVRotate90, Orientation.fromMetadataOrientation("fLiPVRotAte90"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromMetadataOrientationUnknown() {
|
||||||
|
assertEquals(Normal, Orientation.fromMetadataOrientation("foo"));
|
||||||
|
assertEquals(Normal, Orientation.fromMetadataOrientation("90"));
|
||||||
|
assertEquals(Normal, Orientation.fromMetadataOrientation("randomStringWithNumbers180"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromTIFFOrientation() {
|
||||||
|
assertEquals(Normal, Orientation.fromTIFFOrientation(1));
|
||||||
|
assertEquals(FlipH, Orientation.fromTIFFOrientation(2));
|
||||||
|
assertEquals(Rotate180, Orientation.fromTIFFOrientation(3));
|
||||||
|
assertEquals(FlipV, Orientation.fromTIFFOrientation(4));
|
||||||
|
assertEquals(FlipVRotate90, Orientation.fromTIFFOrientation(5));
|
||||||
|
assertEquals(Rotate270, Orientation.fromTIFFOrientation(6));
|
||||||
|
assertEquals(FlipHRotate90, Orientation.fromTIFFOrientation(7));
|
||||||
|
assertEquals(Rotate90, Orientation.fromTIFFOrientation(8));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromTIFFOrientationUnknown() {
|
||||||
|
assertEquals(Normal, Orientation.fromTIFFOrientation(-1));
|
||||||
|
assertEquals(Normal, Orientation.fromTIFFOrientation(0));
|
||||||
|
assertEquals(Normal, Orientation.fromTIFFOrientation(9));
|
||||||
|
for (int i = 10; i < 1024; i++) {
|
||||||
|
assertEquals(Normal, Orientation.fromTIFFOrientation(i));
|
||||||
|
}
|
||||||
|
assertEquals(Normal, Orientation.fromTIFFOrientation(Integer.MAX_VALUE));
|
||||||
|
assertEquals(Normal, Orientation.fromTIFFOrientation(Integer.MIN_VALUE));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.5</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,6 +14,21 @@
|
|||||||
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>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<systemPropertyVariables>
|
||||||
|
<com.twelvemonkeys.imageio.plugins.svg.allowexternalresources>
|
||||||
|
true
|
||||||
|
</com.twelvemonkeys.imageio.plugins.svg.allowexternalresources>
|
||||||
|
</systemPropertyVariables>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -24,6 +39,7 @@
|
|||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio-core</artifactId>
|
<artifactId>imageio-core</artifactId>
|
||||||
<type>test-jar</type>
|
<type>test-jar</type>
|
||||||
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -88,6 +104,6 @@
|
|||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<batik.version>1.9</batik.version>
|
<batik.version>1.14</batik.version>
|
||||||
</properties>
|
</properties>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -33,9 +33,11 @@ package com.twelvemonkeys.imageio.plugins.svg;
|
|||||||
import com.twelvemonkeys.image.ImageUtil;
|
import com.twelvemonkeys.image.ImageUtil;
|
||||||
import com.twelvemonkeys.imageio.ImageReaderBase;
|
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||||
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
import org.apache.batik.anim.dom.SVGDOMImplementation;
|
import org.apache.batik.anim.dom.SVGDOMImplementation;
|
||||||
import org.apache.batik.anim.dom.SVGOMDocument;
|
import org.apache.batik.anim.dom.SVGOMDocument;
|
||||||
import org.apache.batik.bridge.*;
|
import org.apache.batik.bridge.*;
|
||||||
|
import org.apache.batik.css.parser.CSSLexicalUnit;
|
||||||
import org.apache.batik.dom.util.DOMUtilities;
|
import org.apache.batik.dom.util.DOMUtilities;
|
||||||
import org.apache.batik.ext.awt.image.GraphicsUtil;
|
import org.apache.batik.ext.awt.image.GraphicsUtil;
|
||||||
import org.apache.batik.gvt.CanvasGraphicsNode;
|
import org.apache.batik.gvt.CanvasGraphicsNode;
|
||||||
@@ -47,6 +49,7 @@ import org.apache.batik.transcoder.*;
|
|||||||
import org.apache.batik.transcoder.image.ImageTranscoder;
|
import org.apache.batik.transcoder.image.ImageTranscoder;
|
||||||
import org.apache.batik.util.ParsedURL;
|
import org.apache.batik.util.ParsedURL;
|
||||||
import org.apache.batik.util.SVGConstants;
|
import org.apache.batik.util.SVGConstants;
|
||||||
|
import org.apache.batik.xml.LexicalUnits;
|
||||||
import org.w3c.dom.DOMImplementation;
|
import org.w3c.dom.DOMImplementation;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.svg.SVGSVGElement;
|
import org.w3c.dom.svg.SVGSVGElement;
|
||||||
@@ -76,7 +79,12 @@ import java.util.Map;
|
|||||||
* @see <A href="http://www.mail-archive.com/batik-dev@xml.apache.org/msg00992.html">batik-dev</A>
|
* @see <A href="http://www.mail-archive.com/batik-dev@xml.apache.org/msg00992.html">batik-dev</A>
|
||||||
*/
|
*/
|
||||||
public class SVGImageReader extends ImageReaderBase {
|
public class SVGImageReader extends ImageReaderBase {
|
||||||
|
|
||||||
|
final static boolean DEFAULT_ALLOW_EXTERNAL_RESOURCES =
|
||||||
|
"true".equalsIgnoreCase(System.getProperty("com.twelvemonkeys.imageio.plugins.svg.allowexternalresources"));
|
||||||
|
|
||||||
private Rasterizer rasterizer;
|
private Rasterizer rasterizer;
|
||||||
|
private boolean allowExternalResources = DEFAULT_ALLOW_EXTERNAL_RESOURCES;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an {@code SVGImageReader}.
|
* Creates an {@code SVGImageReader}.
|
||||||
@@ -113,6 +121,9 @@ public class SVGImageReader extends ImageReaderBase {
|
|||||||
if (pParam instanceof SVGReadParam) {
|
if (pParam instanceof SVGReadParam) {
|
||||||
SVGReadParam svgParam = (SVGReadParam) pParam;
|
SVGReadParam svgParam = (SVGReadParam) pParam;
|
||||||
|
|
||||||
|
// set the external-resource-resolution preference
|
||||||
|
allowExternalResources = svgParam.isAllowExternalResources();
|
||||||
|
|
||||||
// Get the base URI
|
// Get the base URI
|
||||||
// This must be done before converting the params to hints
|
// This must be done before converting the params to hints
|
||||||
String baseURI = svgParam.getBaseURI();
|
String baseURI = svgParam.getBaseURI();
|
||||||
@@ -324,24 +335,54 @@ public class SVGImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ----
|
// ----
|
||||||
|
SVGSVGElement rootElement = svgDoc.getRootElement();
|
||||||
|
|
||||||
// get the 'width' and 'height' attributes of the SVG document
|
// get the 'width' and 'height' attributes of the SVG document
|
||||||
Dimension2D docSize = ctx.getDocumentSize();
|
UnitProcessor.Context uctx
|
||||||
if (docSize != null) {
|
= UnitProcessor.createContext(ctx, rootElement);
|
||||||
defaultWidth = (float) docSize.getWidth();
|
String widthStr = rootElement.getAttributeNS(null, SVGConstants.SVG_WIDTH_ATTRIBUTE);
|
||||||
defaultHeight = (float) docSize.getHeight();
|
String heightStr = rootElement.getAttributeNS(null, SVGConstants.SVG_HEIGHT_ATTRIBUTE);
|
||||||
|
if (!StringUtil.isEmpty(widthStr)) {
|
||||||
|
defaultWidth = UnitProcessor.svgToUserSpace(widthStr, SVGConstants.SVG_WIDTH_ATTRIBUTE, UnitProcessor.HORIZONTAL_LENGTH, uctx);
|
||||||
}
|
}
|
||||||
else {
|
if(!StringUtil.isEmpty(heightStr)){
|
||||||
defaultWidth = 200;
|
defaultHeight = UnitProcessor.svgToUserSpace(heightStr, SVGConstants.SVG_HEIGHT_ATTRIBUTE, UnitProcessor.VERTICAL_LENGTH, uctx);
|
||||||
defaultHeight = 200;
|
|
||||||
}
|
}
|
||||||
SVGSVGElement rootElement = svgDoc.getRootElement();
|
|
||||||
String viewBoxStr = rootElement.getAttributeNS
|
boolean hasWidth = defaultWidth > 0.0;
|
||||||
(null, SVGConstants.SVG_VIEW_BOX_ATTRIBUTE);
|
boolean hasHeight = defaultHeight > 0.0;
|
||||||
if (viewBoxStr.length() != 0) {
|
|
||||||
float[] rect = ViewBox.parseViewBoxAttribute(rootElement, viewBoxStr, null);
|
if (!hasWidth || !hasHeight) {
|
||||||
defaultWidth = rect[2];
|
String viewBoxStr = rootElement.getAttributeNS
|
||||||
defaultHeight = rect[3];
|
(null, SVGConstants.SVG_VIEW_BOX_ATTRIBUTE);
|
||||||
|
if (viewBoxStr.length() != 0) {
|
||||||
|
float[] rect = ViewBox.parseViewBoxAttribute(rootElement, viewBoxStr, null);
|
||||||
|
// if one dimension is given, calculate other by aspect ratio in viewBox
|
||||||
|
// or use viewBox if no dimension is given
|
||||||
|
if (hasWidth) {
|
||||||
|
defaultHeight = defaultWidth * rect[3] / rect[2];
|
||||||
|
}
|
||||||
|
else if (hasHeight) {
|
||||||
|
defaultWidth = defaultHeight * rect[2] / rect[3];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
defaultWidth = rect[2];
|
||||||
|
defaultHeight = rect[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (hasHeight) {
|
||||||
|
defaultWidth = defaultHeight;
|
||||||
|
}
|
||||||
|
else if (hasWidth) {
|
||||||
|
defaultHeight = defaultWidth;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// fallback to batik default sizes
|
||||||
|
defaultWidth = 400;
|
||||||
|
defaultHeight = 400;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hack to work around exception above
|
// Hack to work around exception above
|
||||||
@@ -608,6 +649,14 @@ public class SVGImageReader extends ImageReaderBase {
|
|||||||
public void displayMessage(String message) {
|
public void displayMessage(String message) {
|
||||||
processWarningOccurred(message.replaceAll("[\\r\\n]+", " "));
|
processWarningOccurred(message.replaceAll("[\\r\\n]+", " "));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExternalResourceSecurity getExternalResourceSecurity(ParsedURL resourceURL, ParsedURL docURL) {
|
||||||
|
if (allowExternalResources) {
|
||||||
|
return super.getExternalResourceSecurity(resourceURL, docURL);
|
||||||
|
}
|
||||||
|
return new NoLoadExternalResourceSecurity();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,11 @@ import java.awt.*;
|
|||||||
public class SVGReadParam extends ImageReadParam {
|
public class SVGReadParam extends ImageReadParam {
|
||||||
private Paint background;
|
private Paint background;
|
||||||
private String baseURI;
|
private String baseURI;
|
||||||
|
private boolean allowExternalResources = SVGImageReader.DEFAULT_ALLOW_EXTERNAL_RESOURCES;
|
||||||
|
|
||||||
|
public SVGReadParam() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
public Paint getBackgroundColor() {
|
public Paint getBackgroundColor() {
|
||||||
return background;
|
return background;
|
||||||
@@ -58,6 +63,14 @@ public class SVGReadParam extends ImageReadParam {
|
|||||||
baseURI = pBaseURI;
|
baseURI = pBaseURI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAllowExternalResources(boolean allow) {
|
||||||
|
allowExternalResources = allow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAllowExternalResources() {
|
||||||
|
return allowExternalResources;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canSetSourceRenderSize() {
|
public boolean canSetSourceRenderSize() {
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.svg;
|
package com.twelvemonkeys.imageio.plugins.svg;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
||||||
|
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -44,12 +45,10 @@ import javax.imageio.stream.ImageInputStream;
|
|||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.ImagingOpException;
|
import java.awt.image.ImagingOpException;
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.Buffer;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -67,30 +66,25 @@ import static org.mockito.Mockito.*;
|
|||||||
* @version $Id: SVGImageReaderTest.java,v 1.0 Apr 1, 2008 10:39:17 PM haraldk Exp$
|
* @version $Id: SVGImageReaderTest.java,v 1.0 Apr 1, 2008 10:39:17 PM haraldk Exp$
|
||||||
*/
|
*/
|
||||||
public class SVGImageReaderTest extends ImageReaderAbstractTest<SVGImageReader> {
|
public class SVGImageReaderTest extends ImageReaderAbstractTest<SVGImageReader> {
|
||||||
private SVGImageReaderSpi provider = new SVGImageReaderSpi();
|
|
||||||
|
@Override
|
||||||
|
protected ImageReaderSpi createProvider() {
|
||||||
|
return new SVGImageReaderSpi();
|
||||||
|
}
|
||||||
|
|
||||||
protected List<TestData> getTestData() {
|
protected List<TestData> getTestData() {
|
||||||
return Arrays.asList(
|
return Arrays.asList(
|
||||||
new TestData(getClassLoaderResource("/svg/batikLogo.svg"), new Dimension(450, 500)),
|
new TestData(getClassLoaderResource("/svg/batikLogo.svg"), new Dimension(450, 500)),
|
||||||
new TestData(getClassLoaderResource("/svg/red-square.svg"), new Dimension(100, 100)),
|
new TestData(getClassLoaderResource("/svg/red-square.svg"), new Dimension(100, 100)),
|
||||||
new TestData(getClassLoaderResource("/svg/blue-square.svg"), new Dimension(100, 100)),
|
new TestData(getClassLoaderResource("/svg/blue-square.svg"), new Dimension(100, 100)),
|
||||||
new TestData(getClassLoaderResource("/svg/Android_robot.svg"), new Dimension(294, 345))
|
new TestData(getClassLoaderResource("/svg/Android_robot.svg"), new Dimension(294, 345)),
|
||||||
|
new TestData(getClassLoaderResource("/svg/sizes/w50h50.svg"), new Dimension(50, 50)),
|
||||||
|
new TestData(getClassLoaderResource("/svg/sizes/w50_1to2.svg"), new Dimension(25, 50)),
|
||||||
|
new TestData(getClassLoaderResource("/svg/sizes/h50_1to2.svg"), new Dimension(50, 100)),
|
||||||
|
new TestData(getClassLoaderResource("/svg/sizes/w50noview.svg"), new Dimension(50, 50))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ImageReaderSpi createProvider() {
|
|
||||||
return provider;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected SVGImageReader createReader() {
|
|
||||||
return new SVGImageReader(createProvider());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Class<SVGImageReader> getReaderClass() {
|
|
||||||
return SVGImageReader.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected List<String> getFormatNames() {
|
protected List<String> getFormatNames() {
|
||||||
return Collections.singletonList("svg");
|
return Collections.singletonList("svg");
|
||||||
}
|
}
|
||||||
@@ -107,8 +101,6 @@ public class SVGImageReaderTest extends ImageReaderAbstractTest<SVGImageReader>
|
|||||||
public void testScaleViewBox() throws IOException {
|
public void testScaleViewBox() throws IOException {
|
||||||
URL svgUrl = getClassLoaderResource("/svg/quadrants.svg");
|
URL svgUrl = getClassLoaderResource("/svg/quadrants.svg");
|
||||||
|
|
||||||
File tmpDir = new File(System.getProperty("java.io.tmpdir"));
|
|
||||||
|
|
||||||
SVGImageReader reader = createReader();
|
SVGImageReader reader = createReader();
|
||||||
SVGReadParam param = new SVGReadParam();
|
SVGReadParam param = new SVGReadParam();
|
||||||
|
|
||||||
@@ -156,11 +148,11 @@ public class SVGImageReaderTest extends ImageReaderAbstractTest<SVGImageReader>
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Override
|
@Override
|
||||||
public void testReadWithSizeParam() {
|
public void testReadWithSizeParam() throws IOException {
|
||||||
try {
|
try {
|
||||||
super.testReadWithSizeParam();
|
super.testReadWithSizeParam();
|
||||||
}
|
}
|
||||||
catch (AssertionError failure) {
|
catch (AssertionError | IOException failure) {
|
||||||
Throwable cause = failure;
|
Throwable cause = failure;
|
||||||
|
|
||||||
while (cause.getCause() != null) {
|
while (cause.getCause() != null) {
|
||||||
@@ -224,6 +216,7 @@ public class SVGImageReaderTest extends ImageReaderAbstractTest<SVGImageReader>
|
|||||||
reader.addIIOReadWarningListener(listener);
|
reader.addIIOReadWarningListener(listener);
|
||||||
|
|
||||||
SVGReadParam param = reader.getDefaultReadParam();
|
SVGReadParam param = reader.getDefaultReadParam();
|
||||||
|
param.setAllowExternalResources(true);
|
||||||
param.setBaseURI(resource.toURI().toASCIIString());
|
param.setBaseURI(resource.toURI().toASCIIString());
|
||||||
BufferedImage image = reader.read(0, param);
|
BufferedImage image = reader.read(0, param);
|
||||||
|
|
||||||
@@ -244,6 +237,8 @@ public class SVGImageReaderTest extends ImageReaderAbstractTest<SVGImageReader>
|
|||||||
// Asking for metadata, width, height etc, before attempting to read using a param,
|
// Asking for metadata, width, height etc, before attempting to read using a param,
|
||||||
// will cause the document to be parsed without a base URI.
|
// will cause the document to be parsed without a base URI.
|
||||||
// This will work, but may not use the CSS...
|
// This will work, but may not use the CSS...
|
||||||
|
// since the param is not available before the read operation is invoked,
|
||||||
|
// this test-case MUST use the system-property for backwards compatibility
|
||||||
URL resource = getClassLoaderResource("/svg/barChart.svg");
|
URL resource = getClassLoaderResource("/svg/barChart.svg");
|
||||||
|
|
||||||
SVGImageReader reader = createReader();
|
SVGImageReader reader = createReader();
|
||||||
@@ -282,18 +277,17 @@ public class SVGImageReaderTest extends ImageReaderAbstractTest<SVGImageReader>
|
|||||||
public void testEmbeddedNoBaseURI() throws IOException {
|
public void testEmbeddedNoBaseURI() throws IOException {
|
||||||
// With no base URI, we will throw an exception, about the missing embedded resource
|
// With no base URI, we will throw an exception, about the missing embedded resource
|
||||||
URL resource = getClassLoaderResource("/svg/barChart.svg");
|
URL resource = getClassLoaderResource("/svg/barChart.svg");
|
||||||
|
|
||||||
SVGImageReader reader = createReader();
|
SVGImageReader reader = createReader();
|
||||||
|
|
||||||
TestData data = new TestData(resource, (Dimension) null);
|
TestData data = new TestData(resource, (Dimension) null);
|
||||||
try (ImageInputStream stream = data.getInputStream()) {
|
try (ImageInputStream stream = data.getInputStream()) {
|
||||||
reader.setInput(stream);
|
reader.setInput(stream);
|
||||||
|
|
||||||
BufferedImage image = reader.read(0);
|
SVGReadParam params = reader.getDefaultReadParam();
|
||||||
|
params.setAllowExternalResources(true);
|
||||||
|
reader.read(0, params);
|
||||||
|
|
||||||
assertNotNull(image);
|
fail("reader.read should've thrown an exception, but didn't");
|
||||||
assertEquals(450, image.getWidth());
|
|
||||||
assertEquals(500, image.getHeight());
|
|
||||||
}
|
}
|
||||||
catch (IIOException allowed) {
|
catch (IIOException allowed) {
|
||||||
assertTrue(allowed.getMessage().contains("batikLogo.svg")); // The embedded resource we don't find
|
assertTrue(allowed.getMessage().contains("batikLogo.svg")); // The embedded resource we don't find
|
||||||
@@ -302,4 +296,28 @@ public class SVGImageReaderTest extends ImageReaderAbstractTest<SVGImageReader>
|
|||||||
reader.dispose();
|
reader.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Test(expected = SecurityException.class)
|
||||||
|
public void testDisallowedExternalResources() throws URISyntaxException, IOException {
|
||||||
|
// system-property set to true in surefire-plugin-settings in the pom
|
||||||
|
URL resource = getClassLoaderResource("/svg/barChart.svg");
|
||||||
|
SVGImageReader reader = createReader();
|
||||||
|
|
||||||
|
TestData data = new TestData(resource, (Dimension) null);
|
||||||
|
try (ImageInputStream stream = data.getInputStream()) {
|
||||||
|
reader.setInput(stream);
|
||||||
|
|
||||||
|
SVGReadParam param = reader.getDefaultReadParam();
|
||||||
|
param.setBaseURI(resource.toURI().toASCIIString());
|
||||||
|
param.setAllowExternalResources(false);
|
||||||
|
// even when the system-property is set to true,
|
||||||
|
// `reader.read` for `/svg/barChart.svg` should raise
|
||||||
|
// a SecurityException when External Resources are blocked
|
||||||
|
// because the API invocation gets preference
|
||||||
|
reader.read(0, param);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
reader.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.wmf;
|
package com.twelvemonkeys.imageio.plugins.wmf;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
||||||
|
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -49,7 +50,10 @@ import java.util.List;
|
|||||||
* @version $Id: WMFImageReaderTest.java,v 1.0 Apr 1, 2008 10:39:17 PM haraldk Exp$
|
* @version $Id: WMFImageReaderTest.java,v 1.0 Apr 1, 2008 10:39:17 PM haraldk Exp$
|
||||||
*/
|
*/
|
||||||
public class WMFImageReaderTest extends ImageReaderAbstractTest<WMFImageReader> {
|
public class WMFImageReaderTest extends ImageReaderAbstractTest<WMFImageReader> {
|
||||||
private WMFImageReaderSpi provider = new WMFImageReaderSpi();
|
@Override
|
||||||
|
protected ImageReaderSpi createProvider() {
|
||||||
|
return new WMFImageReaderSpi();
|
||||||
|
}
|
||||||
|
|
||||||
protected List<TestData> getTestData() {
|
protected List<TestData> getTestData() {
|
||||||
return Collections.singletonList(
|
return Collections.singletonList(
|
||||||
@@ -57,27 +61,17 @@ public class WMFImageReaderTest extends ImageReaderAbstractTest<WMFImageReader>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ImageReaderSpi createProvider() {
|
|
||||||
return provider;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected WMFImageReader createReader() {
|
|
||||||
return new WMFImageReader(createProvider());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Class<WMFImageReader> getReaderClass() {
|
|
||||||
return WMFImageReader.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected List<String> getFormatNames() {
|
protected List<String> getFormatNames() {
|
||||||
return Collections.singletonList("wmf");
|
return Collections.singletonList("wmf");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected List<String> getSuffixes() {
|
protected List<String> getSuffixes() {
|
||||||
return Arrays.asList("wmf", "emf");
|
return Arrays.asList("wmf", "emf");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected List<String> getMIMETypes() {
|
protected List<String> getMIMETypes() {
|
||||||
return Arrays.asList("image/x-wmf", "application/x-msmetafile");
|
return Arrays.asList("image/x-wmf", "application/x-msmetafile");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="50" viewBox="0 0 100 200" version="1.1">
|
||||||
|
<g id="layer1">
|
||||||
|
<rect id="rect2985" width="50" height="50" x="0" y="0"
|
||||||
|
style="color:#000000;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 427 B |
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="50" viewBox="0 0 100 200" version="1.1">
|
||||||
|
<g id="layer1">
|
||||||
|
<rect id="rect2985" width="50" height="50" x="0" y="0"
|
||||||
|
style="color:#000000;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 428 B |
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 100 200" version="1.1">
|
||||||
|
<g id="layer1">
|
||||||
|
<rect id="rect2985" width="50" height="50" x="0" y="0"
|
||||||
|
style="color:#000000;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 439 B |
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="50" version="1.1">
|
||||||
|
<g id="layer1">
|
||||||
|
<rect id="rect2985" width="50" height="50" x="0" y="0"
|
||||||
|
style="color:#000000;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 405 B |
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.5</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>
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio-core</artifactId>
|
<artifactId>imageio-core</artifactId>
|
||||||
<type>test-jar</type>
|
<type>test-jar</type>
|
||||||
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -30,22 +30,6 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.bmp;
|
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.ImageReaderBase;
|
|
||||||
import com.twelvemonkeys.imageio.stream.SubImageInputStream;
|
|
||||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
|
||||||
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
|
||||||
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
|
||||||
import com.twelvemonkeys.io.LittleEndianDataInputStream;
|
|
||||||
import com.twelvemonkeys.io.enc.DecoderStream;
|
|
||||||
import com.twelvemonkeys.xml.XMLSerializer;
|
|
||||||
|
|
||||||
import javax.imageio.*;
|
|
||||||
import javax.imageio.event.IIOReadUpdateListener;
|
|
||||||
import javax.imageio.event.IIOReadWarningListener;
|
|
||||||
import javax.imageio.metadata.IIOMetadata;
|
|
||||||
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
|
||||||
import javax.imageio.spi.ImageReaderSpi;
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.color.ColorSpace;
|
import java.awt.color.ColorSpace;
|
||||||
import java.awt.image.*;
|
import java.awt.image.*;
|
||||||
@@ -56,6 +40,27 @@ import java.nio.ByteOrder;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.imageio.ImageReadParam;
|
||||||
|
import javax.imageio.ImageReader;
|
||||||
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
|
import javax.imageio.event.IIOReadUpdateListener;
|
||||||
|
import javax.imageio.event.IIOReadWarningListener;
|
||||||
|
import javax.imageio.metadata.IIOMetadata;
|
||||||
|
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
||||||
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||||
|
import com.twelvemonkeys.imageio.stream.SubImageInputStream;
|
||||||
|
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||||
|
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
||||||
|
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
||||||
|
import com.twelvemonkeys.io.LittleEndianDataInputStream;
|
||||||
|
import com.twelvemonkeys.io.enc.DecoderStream;
|
||||||
|
import com.twelvemonkeys.xml.XMLSerializer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ImageReader for Microsoft Windows Bitmap (BMP) format.
|
* ImageReader for Microsoft Windows Bitmap (BMP) format.
|
||||||
*
|
*
|
||||||
@@ -125,6 +130,10 @@ public final class BMPImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
// Read DIB header
|
// Read DIB header
|
||||||
header = DIBHeader.read(imageInput);
|
header = DIBHeader.read(imageInput);
|
||||||
|
|
||||||
|
if (pixelOffset < header.size + DIB.BMP_FILE_HEADER_SIZE) {
|
||||||
|
throw new IIOException("Invalid pixel offset: " + pixelOffset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,50 +216,55 @@ public final class BMPImageReader extends ImageReaderBase {
|
|||||||
throw new IIOException("Multiple planes not supported");
|
throw new IIOException("Multiple planes not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (header.getBitCount()) {
|
try {
|
||||||
case 1:
|
switch (header.getBitCount()) {
|
||||||
case 2:
|
case 1:
|
||||||
case 4:
|
case 2:
|
||||||
case 8:
|
case 4:
|
||||||
return ImageTypeSpecifiers.createFromIndexColorModel(readColorMap());
|
case 8:
|
||||||
|
return ImageTypeSpecifiers.createFromIndexColorModel(readColorMap());
|
||||||
|
|
||||||
case 16:
|
case 16:
|
||||||
if (header.hasMasks()) {
|
if (header.hasMasks()) {
|
||||||
return ImageTypeSpecifiers.createPacked(
|
return ImageTypeSpecifiers.createPacked(
|
||||||
ColorSpace.getInstance(ColorSpace.CS_sRGB),
|
ColorSpace.getInstance(ColorSpace.CS_sRGB),
|
||||||
header.masks[0], header.masks[1], header.masks[2], header.masks[3],
|
header.masks[0], header.masks[1], header.masks[2], header.masks[3],
|
||||||
DataBuffer.TYPE_USHORT, false
|
DataBuffer.TYPE_USHORT, false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default if no mask is 555
|
// Default if no mask is 555
|
||||||
return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_USHORT_555_RGB);
|
return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_USHORT_555_RGB);
|
||||||
|
|
||||||
case 24:
|
case 24:
|
||||||
if (header.getCompression() != DIB.COMPRESSION_RGB) {
|
if (header.getCompression() != DIB.COMPRESSION_RGB) {
|
||||||
throw new IIOException("Unsupported compression for RGB: " + header.getCompression());
|
throw new IIOException("Unsupported compression for RGB: " + header.getCompression());
|
||||||
}
|
}
|
||||||
|
|
||||||
return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR);
|
return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR);
|
||||||
|
|
||||||
case 32:
|
case 32:
|
||||||
if (header.hasMasks()) {
|
if (header.hasMasks()) {
|
||||||
return ImageTypeSpecifiers.createPacked(
|
return ImageTypeSpecifiers.createPacked(
|
||||||
ColorSpace.getInstance(ColorSpace.CS_sRGB),
|
ColorSpace.getInstance(ColorSpace.CS_sRGB),
|
||||||
header.masks[0], header.masks[1], header.masks[2], header.masks[3],
|
header.masks[0], header.masks[1], header.masks[2], header.masks[3],
|
||||||
DataBuffer.TYPE_INT, false
|
DataBuffer.TYPE_INT, false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default if no mask
|
// Default if no mask
|
||||||
return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);
|
return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);
|
||||||
|
|
||||||
case 0:
|
case 0:
|
||||||
if (header.getCompression() == DIB.COMPRESSION_JPEG || header.getCompression() == DIB.COMPRESSION_PNG) {
|
if (header.getCompression() == DIB.COMPRESSION_JPEG || header.getCompression() == DIB.COMPRESSION_PNG) {
|
||||||
return initReaderDelegate(header.getCompression()).getRawImageType(0);
|
return initReaderDelegate(header.getCompression()).getRawImageType(0);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
throw new IIOException("Unsupported bit count: " + header.getBitCount());
|
throw new IIOException("Unsupported bit count: " + header.getBitCount());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException e) {
|
||||||
|
throw new IIOException(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,9 +33,13 @@ package com.twelvemonkeys.imageio.plugins.bmp;
|
|||||||
import com.twelvemonkeys.imageio.spi.ImageWriterSpiBase;
|
import com.twelvemonkeys.imageio.spi.ImageWriterSpiBase;
|
||||||
|
|
||||||
import javax.imageio.ImageTypeSpecifier;
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
import java.io.IOException;
|
import javax.imageio.spi.ImageWriterSpi;
|
||||||
|
import javax.imageio.spi.ServiceRegistry;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import static com.twelvemonkeys.imageio.util.IIOUtil.lookupProviderByName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BMPImageWriterSpi
|
* BMPImageWriterSpi
|
||||||
*/
|
*/
|
||||||
@@ -45,17 +49,28 @@ public final class BMPImageWriterSpi extends ImageWriterSpiBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canEncodeImage(final ImageTypeSpecifier type) {
|
public void onRegistration(ServiceRegistry registry, Class<?> category) {
|
||||||
return true;
|
// Make sure we register BEHIND the built-in BMP writer
|
||||||
|
ImageWriterSpi sunSpi = lookupProviderByName(registry, "com.sun.imageio.plugins.bmp.BMPImageWriterSpi", ImageWriterSpi.class);
|
||||||
|
|
||||||
|
if (sunSpi != null && sunSpi.getVendorName() != null) {
|
||||||
|
registry.setOrdering((Class<ImageWriterSpi>) category, sunSpi, this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BMPImageWriter createWriterInstance(final Object extension) throws IOException {
|
public boolean canEncodeImage(final ImageTypeSpecifier type) {
|
||||||
|
// TODO: Support more types, as time permits.
|
||||||
|
return type.getBufferedImageType() == BufferedImage.TYPE_4BYTE_ABGR;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BMPImageWriter createWriterInstance(final Object extension) {
|
||||||
return new BMPImageWriter(this);
|
return new BMPImageWriter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDescription(final Locale locale) {
|
public String getDescription(final Locale locale) {
|
||||||
return "Windows Device Independent Bitmap Format (BMP) Reader";
|
return "Windows Device Independent Bitmap Format (BMP) Writer";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ import javax.imageio.metadata.IIOMetadataNode;
|
|||||||
* BMPMetadata.
|
* BMPMetadata.
|
||||||
*/
|
*/
|
||||||
final class BMPMetadata extends AbstractMetadata {
|
final class BMPMetadata extends AbstractMetadata {
|
||||||
/** We return metadata in the exact same form as the JRE built-in, to be compatible with the DIBImageWriter. */
|
/** We return metadata in the exact same form as the JRE built-in, to be compatible with the BMPImageWriter. */
|
||||||
public static final String nativeMetadataFormatName = "javax_imageio_bmp_1.0";
|
public static final String nativeMetadataFormatName = "javax_imageio_bmp_1.0";
|
||||||
|
|
||||||
private final DIBHeader header;
|
private final DIBHeader header;
|
||||||
|
|||||||
@@ -29,9 +29,10 @@
|
|||||||
*/
|
*/
|
||||||
package com.twelvemonkeys.imageio.plugins.bmp;
|
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||||
|
|
||||||
import com.twelvemonkeys.lang.Validate;
|
import static com.twelvemonkeys.lang.Validate.notNull;
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Describes a bitmap structure.
|
* Describes a bitmap structure.
|
||||||
@@ -47,14 +48,11 @@ abstract class BitmapDescriptor {
|
|||||||
protected BitmapMask mask;
|
protected BitmapMask mask;
|
||||||
|
|
||||||
public BitmapDescriptor(final DirectoryEntry pEntry, final DIBHeader pHeader) {
|
public BitmapDescriptor(final DirectoryEntry pEntry, final DIBHeader pHeader) {
|
||||||
Validate.notNull(pEntry, "entry");
|
entry = notNull(pEntry, "entry");;
|
||||||
Validate.notNull(pHeader, "header");
|
header = notNull(pHeader, "header");
|
||||||
|
|
||||||
entry = pEntry;
|
|
||||||
header = pHeader;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract public BufferedImage getImage();
|
abstract public BufferedImage getImage() throws IOException;
|
||||||
|
|
||||||
public final int getWidth() {
|
public final int getWidth() {
|
||||||
return entry.getWidth();
|
return entry.getWidth();
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ class BitmapIndexed extends BitmapDescriptor {
|
|||||||
return transparent;
|
return transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public BufferedImage getImage() {
|
public BufferedImage getImage() {
|
||||||
if (image == null) {
|
if (image == null) {
|
||||||
image = createImageIndexed();
|
image = createImageIndexed();
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ class BitmapRGB extends BitmapDescriptor {
|
|||||||
super(pEntry, pHeader);
|
super(pEntry, pHeader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public BufferedImage getImage() {
|
public BufferedImage getImage() {
|
||||||
// Test is mask != null rather than hasMask(), as 32 bit (w/alpha)
|
// Test is mask != null rather than hasMask(), as 32 bit (w/alpha)
|
||||||
// might still have bitmask, but we don't read or use it.
|
// might still have bitmask, but we don't read or use it.
|
||||||
|
|||||||
@@ -31,6 +31,9 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.bmp;
|
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents bitmap structures we can't read.
|
* Represents bitmap structures we can't read.
|
||||||
@@ -42,13 +45,14 @@ import java.awt.image.BufferedImage;
|
|||||||
class BitmapUnsupported extends BitmapDescriptor {
|
class BitmapUnsupported extends BitmapDescriptor {
|
||||||
private String message;
|
private String message;
|
||||||
|
|
||||||
public BitmapUnsupported(final DirectoryEntry pEntry, final String pMessage) {
|
public BitmapUnsupported(final DirectoryEntry pEntry, DIBHeader header, final String pMessage) {
|
||||||
super(pEntry, null);
|
super(pEntry, header);
|
||||||
|
|
||||||
message = pMessage;
|
message = pMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BufferedImage getImage() {
|
@Override
|
||||||
throw new IllegalStateException(message);
|
public BufferedImage getImage() throws IOException {
|
||||||
|
throw new IIOException(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,11 +30,12 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.bmp;
|
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the DIB (Device Independent Bitmap) Information header structure.
|
* Represents the DIB (Device Independent Bitmap) Information header structure.
|
||||||
*
|
*
|
||||||
@@ -213,7 +214,7 @@ abstract class DIBHeader {
|
|||||||
|
|
||||||
// NOTE: Unlike all other headers, width and height are unsigned SHORT values (16 bit)!
|
// NOTE: Unlike all other headers, width and height are unsigned SHORT values (16 bit)!
|
||||||
width = pStream.readUnsignedShort();
|
width = pStream.readUnsignedShort();
|
||||||
height = pStream.readUnsignedShort();
|
height = pStream.readShort();
|
||||||
|
|
||||||
if (height < 0) {
|
if (height < 0) {
|
||||||
height = -height;
|
height = -height;
|
||||||
@@ -240,6 +241,7 @@ abstract class DIBHeader {
|
|||||||
* @see <a href="http://www.fileformat.info/format/os2bmp/egff.htm">OS/2 Bitmap File Format Summary</a>
|
* @see <a href="http://www.fileformat.info/format/os2bmp/egff.htm">OS/2 Bitmap File Format Summary</a>
|
||||||
*/
|
*/
|
||||||
static final class BitmapCoreHeaderV2 extends DIBHeader {
|
static final class BitmapCoreHeaderV2 extends DIBHeader {
|
||||||
|
@SuppressWarnings("unused")
|
||||||
protected void read(final int pSize, final DataInput pStream) throws IOException {
|
protected void read(final int pSize, final DataInput pStream) throws IOException {
|
||||||
if (pSize != DIB.OS2_V2_HEADER_SIZE && pSize != DIB.OS2_V2_HEADER_16_SIZE) {
|
if (pSize != DIB.OS2_V2_HEADER_SIZE && pSize != DIB.OS2_V2_HEADER_16_SIZE) {
|
||||||
throw new IIOException(String.format("Size: %s !=: %s", pSize, DIB.OS2_V2_HEADER_SIZE));
|
throw new IIOException(String.format("Size: %s !=: %s", pSize, DIB.OS2_V2_HEADER_SIZE));
|
||||||
|
|||||||
@@ -30,16 +30,6 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.bmp;
|
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||||
|
|
||||||
import com.twelvemonkeys.image.ImageUtil;
|
|
||||||
import com.twelvemonkeys.imageio.ImageReaderBase;
|
|
||||||
import com.twelvemonkeys.imageio.stream.SubImageInputStream;
|
|
||||||
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
|
||||||
import com.twelvemonkeys.util.WeakWeakMap;
|
|
||||||
|
|
||||||
import javax.imageio.*;
|
|
||||||
import javax.imageio.spi.ImageReaderSpi;
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
|
||||||
import javax.swing.*;
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.color.ColorSpace;
|
import java.awt.color.ColorSpace;
|
||||||
import java.awt.event.WindowAdapter;
|
import java.awt.event.WindowAdapter;
|
||||||
@@ -48,8 +38,26 @@ import java.awt.image.*;
|
|||||||
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.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.*;
|
import java.util.Map;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.imageio.ImageReadParam;
|
||||||
|
import javax.imageio.ImageReader;
|
||||||
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import javax.swing.*;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.image.ImageUtil;
|
||||||
|
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||||
|
import com.twelvemonkeys.imageio.stream.SubImageInputStream;
|
||||||
|
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
||||||
|
import com.twelvemonkeys.util.WeakWeakMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ImageReader for Microsoft Windows ICO (icon) format.
|
* ImageReader for Microsoft Windows ICO (icon) format.
|
||||||
@@ -84,7 +92,7 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
protected void resetMembers() {
|
protected void resetMembers() {
|
||||||
directory = null;
|
directory = null;
|
||||||
|
|
||||||
headers.clear();
|
headers.clear();
|
||||||
descriptors.clear();
|
descriptors.clear();
|
||||||
|
|
||||||
@@ -287,7 +295,7 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
// TODO: Support this, it's already in the BMP reader, spec allows RLE4 and RLE8
|
// TODO: Support this, it's already in the BMP reader, spec allows RLE4 and RLE8
|
||||||
if (header.getCompression() != DIB.COMPRESSION_RGB) {
|
if (header.getCompression() != DIB.COMPRESSION_RGB) {
|
||||||
descriptor = new BitmapUnsupported(pEntry, String.format("Unsupported compression: %d", header.getCompression()));
|
descriptor = new BitmapUnsupported(pEntry, header, String.format("Unsupported compression: %d", header.getCompression()));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int bitCount = header.getBitCount();
|
int bitCount = header.getBitCount();
|
||||||
@@ -315,7 +323,7 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
descriptor = new BitmapUnsupported(pEntry, String.format("Unsupported bit count %d", bitCount));
|
descriptor = new BitmapUnsupported(pEntry, header, String.format("Unsupported bit count %d", bitCount));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,7 +363,7 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void readBitmapIndexed1(final BitmapIndexed pBitmap, final boolean pAsMask) throws IOException {
|
private void readBitmapIndexed1(final BitmapIndexed pBitmap, final boolean pAsMask) throws IOException {
|
||||||
int width = adjustToPadding(pBitmap.getWidth() >> 3);
|
int width = adjustToPadding((pBitmap.getWidth() + 7) >> 3);
|
||||||
byte[] row = new byte[width];
|
byte[] row = new byte[width];
|
||||||
|
|
||||||
for (int y = 0; y < pBitmap.getHeight(); y++) {
|
for (int y = 0; y < pBitmap.getHeight(); y++) {
|
||||||
@@ -389,7 +397,7 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void readBitmapIndexed4(final BitmapIndexed pBitmap) throws IOException {
|
private void readBitmapIndexed4(final BitmapIndexed pBitmap) throws IOException {
|
||||||
int width = adjustToPadding(pBitmap.getWidth() >> 1);
|
int width = adjustToPadding((pBitmap.getWidth() + 1) >> 1);
|
||||||
byte[] row = new byte[width];
|
byte[] row = new byte[width];
|
||||||
|
|
||||||
for (int y = 0; y < pBitmap.getHeight(); y++) {
|
for (int y = 0; y < pBitmap.getHeight(); y++) {
|
||||||
@@ -457,13 +465,12 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void readBitmap16(final BitmapDescriptor pBitmap) throws IOException {
|
private void readBitmap16(final BitmapDescriptor pBitmap) throws IOException {
|
||||||
// TODO: No idea if this actually works..
|
|
||||||
short[] pixels = new short[pBitmap.getWidth() * pBitmap.getHeight()];
|
short[] pixels = new short[pBitmap.getWidth() * pBitmap.getHeight()];
|
||||||
|
|
||||||
// TODO: Support TYPE_USHORT_565 and the RGB 444/ARGB 4444 layouts
|
// TODO: Support TYPE_USHORT_565 and the RGB 444/ARGB 4444 layouts
|
||||||
// Will create TYPE_USHORT_555
|
// Will create TYPE_USHORT_555
|
||||||
DirectColorModel cm = new DirectColorModel(16, 0x7C00, 0x03E0, 0x001F);
|
DirectColorModel cm = new DirectColorModel(16, 0x7C00, 0x03E0, 0x001F);
|
||||||
DataBuffer buffer = new DataBufferShort(pixels, pixels.length);
|
DataBuffer buffer = new DataBufferUShort(pixels, pixels.length);
|
||||||
WritableRaster raster = Raster.createPackedRaster(
|
WritableRaster raster = Raster.createPackedRaster(
|
||||||
buffer, pBitmap.getWidth(), pBitmap.getHeight(), pBitmap.getWidth(), cm.getMasks(), null
|
buffer, pBitmap.getWidth(), pBitmap.getHeight(), pBitmap.getWidth(), cm.getMasks(), null
|
||||||
);
|
);
|
||||||
@@ -551,7 +558,7 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
if (abortRequested()) {
|
if (abortRequested()) {
|
||||||
processReadAborted();
|
processReadAborted();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
processImageProgress(100 * y / (float) pBitmap.getHeight());
|
processImageProgress(100 * y / (float) pBitmap.getHeight());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -591,7 +598,7 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
return directory.getEntry(pImageIndex);
|
return directory.getEntry(pImageIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test code below, ignore.. :-)
|
/// Test code below, ignore.. :-)
|
||||||
public static void main(final String[] pArgs) throws IOException {
|
public static void main(final String[] pArgs) throws IOException {
|
||||||
if (pArgs.length == 0) {
|
if (pArgs.length == 0) {
|
||||||
@@ -701,10 +708,10 @@ abstract class DIBImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
button.setText("" + image.getWidth() + "x" +
|
button.setText(image.getWidth() + "x" +
|
||||||
image.getHeight() + ": "
|
image.getHeight() + ": "
|
||||||
+ ((image.getColorModel() instanceof IndexColorModel) ?
|
+ ((image.getColorModel() instanceof IndexColorModel) ?
|
||||||
"" + ((IndexColorModel) image.getColorModel()).getMapSize() :
|
String.valueOf(((IndexColorModel) image.getColorModel()).getMapSize()) :
|
||||||
"TrueColor"));
|
"TrueColor"));
|
||||||
|
|
||||||
pParent.add(button);
|
pParent.add(button);
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import java.nio.ByteOrder;
|
|||||||
* DIBImageWriter
|
* DIBImageWriter
|
||||||
*/
|
*/
|
||||||
abstract class DIBImageWriter extends ImageWriterBase {
|
abstract class DIBImageWriter extends ImageWriterBase {
|
||||||
|
|
||||||
DIBImageWriter(ImageWriterSpi provider) {
|
DIBImageWriter(ImageWriterSpi provider) {
|
||||||
super(provider);
|
super(provider);
|
||||||
}
|
}
|
||||||
@@ -50,7 +51,9 @@ abstract class DIBImageWriter extends ImageWriterBase {
|
|||||||
@Override
|
@Override
|
||||||
public void setOutput(Object output) {
|
public void setOutput(Object output) {
|
||||||
super.setOutput(output);
|
super.setOutput(output);
|
||||||
imageOutput.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
if (imageOutput != null) {
|
||||||
|
imageOutput.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeDIBHeader(int infoHeaderSize, int width, int height, boolean isTopDown, int pixelSize, int compression) throws IOException {
|
void writeDIBHeader(int infoHeaderSize, int width, int height, boolean isTopDown, int pixelSize, int compression) throws IOException {
|
||||||
@@ -82,9 +85,8 @@ abstract class DIBImageWriter extends ImageWriterBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void writeUncompressed(boolean isTopDown, BufferedImage img, int height, int width) throws IOException {
|
void writeUncompressed(boolean isTopDown, BufferedImage img, int height, int width) throws IOException {
|
||||||
// TODO: Fix
|
|
||||||
if (img.getType() != BufferedImage.TYPE_4BYTE_ABGR) {
|
if (img.getType() != BufferedImage.TYPE_4BYTE_ABGR) {
|
||||||
throw new IIOException("Blows!");
|
throw new IIOException("Only TYPE_4BYTE_ABGR supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Support
|
// Support
|
||||||
@@ -93,12 +95,13 @@ abstract class DIBImageWriter extends ImageWriterBase {
|
|||||||
// - TODO: Packed/DirectColorModel (16 and 32 bit, BI_BITFIELDS, BI_PNG? BI_JPEG?)
|
// - TODO: Packed/DirectColorModel (16 and 32 bit, BI_BITFIELDS, BI_PNG? BI_JPEG?)
|
||||||
|
|
||||||
Raster raster = img.getRaster();
|
Raster raster = img.getRaster();
|
||||||
WritableRaster rowRaster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, 1, width * 4, 4, new int[]{2, 1, 0, 3}, null);
|
WritableRaster rowRaster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, 1, width * 4, 4, new int[] {2, 1, 0, 3}, null);
|
||||||
byte[] row = ((DataBufferByte) rowRaster.getDataBuffer()).getData();
|
byte[] row = ((DataBufferByte) rowRaster.getDataBuffer()).getData();
|
||||||
|
final int[] bandList = {2, 1, 0, 3};
|
||||||
|
|
||||||
for (int i = 0; i < height; i++) {
|
for (int i = 0; i < height; i++) {
|
||||||
int line = isTopDown ? i : height - 1 - i;
|
int line = isTopDown ? i : height - 1 - i;
|
||||||
rowRaster.setDataElements(0, 0, raster.createChild(0, line, width, 1, 0, 0, new int[]{2, 1, 0, 3}));
|
rowRaster.setDataElements(0, 0, raster.createChild(0, line, width, 1, 0, 0, bandList));
|
||||||
|
|
||||||
imageOutput.write(row);
|
imageOutput.write(row);
|
||||||
|
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ public final class ICOImageWriter extends DIBImageWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (image.hasRaster()) {
|
if (image.hasRaster()) {
|
||||||
throw new UnsupportedOperationException("image has a Raster");
|
throw new UnsupportedOperationException("Raster not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sequenceIndex >= INITIAL_ENTRY_COUNT) {
|
if (sequenceIndex >= INITIAL_ENTRY_COUNT) {
|
||||||
@@ -155,7 +155,7 @@ public final class ICOImageWriter extends DIBImageWriter {
|
|||||||
ColorModel colorModel = image.getRenderedImage().getColorModel();
|
ColorModel colorModel = image.getRenderedImage().getColorModel();
|
||||||
|
|
||||||
// TODO: The output size may depend on the param (subsampling, source region, etc)
|
// TODO: The output size may depend on the param (subsampling, source region, etc)
|
||||||
if (width > ICO_MAX_DIMENSION && height > ICO_MAX_DIMENSION) {
|
if (width > ICO_MAX_DIMENSION || height > ICO_MAX_DIMENSION) {
|
||||||
throw new IIOException(String.format("ICO maximum width or height (%d) exceeded", ICO_MAX_DIMENSION));
|
throw new IIOException(String.format("ICO maximum width or height (%d) exceeded", ICO_MAX_DIMENSION));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ package com.twelvemonkeys.imageio.plugins.bmp;
|
|||||||
import com.twelvemonkeys.imageio.spi.ImageWriterSpiBase;
|
import com.twelvemonkeys.imageio.spi.ImageWriterSpiBase;
|
||||||
|
|
||||||
import javax.imageio.ImageTypeSpecifier;
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
import java.io.IOException;
|
import java.awt.image.BufferedImage;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -46,11 +46,13 @@ public final class ICOImageWriterSpi extends ImageWriterSpiBase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canEncodeImage(final ImageTypeSpecifier type) {
|
public boolean canEncodeImage(final ImageTypeSpecifier type) {
|
||||||
return true;
|
// TODO: Support more types, as time permits.
|
||||||
|
// NOTE: We do support more types, if writing using PNG compression
|
||||||
|
return type.getBufferedImageType() == BufferedImage.TYPE_4BYTE_ABGR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ICOImageWriter createWriterInstance(final Object extension) throws IOException {
|
public ICOImageWriter createWriterInstance(final Object extension) {
|
||||||
return new ICOImageWriter(this);
|
return new ICOImageWriter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ import java.util.Arrays;
|
|||||||
* @version $Id: RLE4Decoder.java#1 $
|
* @version $Id: RLE4Decoder.java#1 $
|
||||||
*/
|
*/
|
||||||
final class RLE4Decoder extends AbstractRLEDecoder {
|
final class RLE4Decoder extends AbstractRLEDecoder {
|
||||||
final static int BIT_MASKS[] = {0xf0, 0x0f};
|
final static int[] BIT_MASKS = {0xf0, 0x0f};
|
||||||
final static int BIT_SHIFTS[] = {4, 0};
|
final static int[] BIT_SHIFTS = {4, 0};
|
||||||
|
|
||||||
public RLE4Decoder(final int width) {
|
public RLE4Decoder(final int width) {
|
||||||
super(width, 4);
|
super(width, 4);
|
||||||
@@ -94,7 +94,7 @@ final class RLE4Decoder extends AbstractRLEDecoder {
|
|||||||
boolean paddingByte = (((byte2 + 1) / 2) % 2) != 0;
|
boolean paddingByte = (((byte2 + 1) / 2) % 2) != 0;
|
||||||
|
|
||||||
int packed = 0;
|
int packed = 0;
|
||||||
for (int i = 0; i < byte2; i++) {
|
for (int i = 0; i < byte2 && srcX / 2 < row.length; i++) {
|
||||||
if (i % 2 == 0) {
|
if (i % 2 == 0) {
|
||||||
packed = checkEOF(stream.read());
|
packed = checkEOF(stream.read());
|
||||||
}
|
}
|
||||||
@@ -111,7 +111,7 @@ final class RLE4Decoder extends AbstractRLEDecoder {
|
|||||||
else {
|
else {
|
||||||
// Encoded mode
|
// Encoded mode
|
||||||
// Replicate the two samples in byte2 as many times as byte1 says
|
// Replicate the two samples in byte2 as many times as byte1 says
|
||||||
for (int i = 0; i < byte1; i++) {
|
for (int i = 0; i < byte1 && srcX / 2 < row.length; i++) {
|
||||||
row[srcX / 2] |= (byte) (((byte2 & BIT_MASKS[i % 2]) >> BIT_SHIFTS[i % 2]) << BIT_SHIFTS[srcX % 2]);
|
row[srcX / 2] |= (byte) (((byte2 & BIT_MASKS[i % 2]) >> BIT_SHIFTS[i % 2]) << BIT_SHIFTS[srcX % 2]);
|
||||||
srcX++;
|
srcX++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ final class RLE8Decoder extends AbstractRLEDecoder {
|
|||||||
// an additional padding byte is in the stream and must be skipped
|
// an additional padding byte is in the stream and must be skipped
|
||||||
boolean paddingByte = (byte2 % 2) != 0;
|
boolean paddingByte = (byte2 % 2) != 0;
|
||||||
|
|
||||||
while (byte2-- > 0) {
|
while (byte2-- > 0 && srcX < row.length) {
|
||||||
row[srcX++] = (byte) checkEOF(stream.read());
|
row[srcX++] = (byte) checkEOF(stream.read());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ final class RLE8Decoder extends AbstractRLEDecoder {
|
|||||||
// Encoded mode
|
// Encoded mode
|
||||||
// Replicate byte2 as many times as byte1 says
|
// Replicate byte2 as many times as byte1 says
|
||||||
byte value = (byte) byte2;
|
byte value = (byte) byte2;
|
||||||
while (byte1-- > 0) {
|
while (byte1-- > 0 && srcX < row.length) {
|
||||||
row[srcX++] = value;
|
row[srcX++] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,35 +30,43 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.bmp;
|
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
import static org.junit.Assert.*;
|
||||||
import com.twelvemonkeys.xml.XMLSerializer;
|
import static org.junit.Assume.assumeNoException;
|
||||||
|
import static org.mockito.Matchers.anyInt;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.atLeastOnce;
|
||||||
|
import static org.mockito.Mockito.inOrder;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.imageio.ImageReadParam;
|
||||||
|
import javax.imageio.ImageReader;
|
||||||
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
|
import javax.imageio.event.IIOReadProgressListener;
|
||||||
|
import javax.imageio.metadata.IIOMetadata;
|
||||||
|
import javax.imageio.metadata.IIOMetadataNode;
|
||||||
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
|
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.InOrder;
|
import org.mockito.InOrder;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
|
|
||||||
import javax.imageio.*;
|
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
||||||
import javax.imageio.event.IIOReadProgressListener;
|
import com.twelvemonkeys.xml.XMLSerializer;
|
||||||
import javax.imageio.metadata.IIOMetadata;
|
|
||||||
import javax.imageio.metadata.IIOMetadataNode;
|
|
||||||
import javax.imageio.spi.ImageReaderSpi;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
import static org.junit.Assume.assumeNoException;
|
|
||||||
import static org.mockito.Matchers.anyInt;
|
|
||||||
import static org.mockito.Matchers.eq;
|
|
||||||
import static org.mockito.Mockito.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BMPImageReaderTest
|
* BMPImageReaderTest
|
||||||
@@ -68,6 +76,12 @@ import static org.mockito.Mockito.*;
|
|||||||
* @version $Id: BMPImageReaderTest.java,v 1.0 Apr 1, 2008 10:39:17 PM haraldk Exp$
|
* @version $Id: BMPImageReaderTest.java,v 1.0 Apr 1, 2008 10:39:17 PM haraldk Exp$
|
||||||
*/
|
*/
|
||||||
public class BMPImageReaderTest extends ImageReaderAbstractTest<BMPImageReader> {
|
public class BMPImageReaderTest extends ImageReaderAbstractTest<BMPImageReader> {
|
||||||
|
@Override
|
||||||
|
protected ImageReaderSpi createProvider() {
|
||||||
|
return new BMPImageReaderSpi();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected List<TestData> getTestData() {
|
protected List<TestData> getTestData() {
|
||||||
return Arrays.asList(
|
return Arrays.asList(
|
||||||
// BMP Suite "Good"
|
// BMP Suite "Good"
|
||||||
@@ -144,27 +158,17 @@ public class BMPImageReaderTest extends ImageReaderAbstractTest<BMPImageReader>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ImageReaderSpi createProvider() {
|
|
||||||
return new BMPImageReaderSpi();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected BMPImageReader createReader() {
|
|
||||||
return new BMPImageReader(createProvider());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Class<BMPImageReader> getReaderClass() {
|
|
||||||
return BMPImageReader.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected List<String> getFormatNames() {
|
protected List<String> getFormatNames() {
|
||||||
return Collections.singletonList("bmp");
|
return Collections.singletonList("bmp");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected List<String> getSuffixes() {
|
protected List<String> getSuffixes() {
|
||||||
return Arrays.asList("bmp", "rle");
|
return Arrays.asList("bmp", "rle");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected List<String> getMIMETypes() {
|
protected List<String> getMIMETypes() {
|
||||||
return Collections.singletonList("image/bmp");
|
return Collections.singletonList("image/bmp");
|
||||||
}
|
}
|
||||||
@@ -178,7 +182,7 @@ public class BMPImageReaderTest extends ImageReaderAbstractTest<BMPImageReader>
|
|||||||
|
|
||||||
ImageTypeSpecifier rawType = reader.getRawImageType(0);
|
ImageTypeSpecifier rawType = reader.getRawImageType(0);
|
||||||
|
|
||||||
// As the JPEGImageReader we delegate to returns null for YCbCr, we'll have to do the same
|
// As the JPEGImageReader we delegate to may return null for YCbCr, we'll have to do the same
|
||||||
if (rawType == null && data.getInput().toString().contains("jpeg")) {
|
if (rawType == null && data.getInput().toString().contains("jpeg")) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -273,7 +277,7 @@ public class BMPImageReaderTest extends ImageReaderAbstractTest<BMPImageReader>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddIIOReadProgressListenerCallbacksJPEG() {
|
public void testAddIIOReadProgressListenerCallbacksJPEG() throws IOException {
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
TestData data = new TestData(getClassLoaderResource("/bmpsuite/q/rgb24jpeg.bmp"), new Dimension(127, 64));
|
TestData data = new TestData(getClassLoaderResource("/bmpsuite/q/rgb24jpeg.bmp"), new Dimension(127, 64));
|
||||||
reader.setInput(data.getInputStream());
|
reader.setInput(data.getInputStream());
|
||||||
@@ -296,7 +300,7 @@ public class BMPImageReaderTest extends ImageReaderAbstractTest<BMPImageReader>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddIIOReadProgressListenerCallbacksPNG() {
|
public void testAddIIOReadProgressListenerCallbacksPNG() throws IOException {
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
TestData data = new TestData(getClassLoaderResource("/bmpsuite/q/rgb24png.bmp"), new Dimension(127, 64));
|
TestData data = new TestData(getClassLoaderResource("/bmpsuite/q/rgb24png.bmp"), new Dimension(127, 64));
|
||||||
reader.setInput(data.getInputStream());
|
reader.setInput(data.getInputStream());
|
||||||
@@ -319,7 +323,7 @@ public class BMPImageReaderTest extends ImageReaderAbstractTest<BMPImageReader>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMetadataEqualsJRE() throws IOException, URISyntaxException {
|
public void testMetadataEqualsJRE() throws IOException {
|
||||||
ImageReader jreReader;
|
ImageReader jreReader;
|
||||||
try {
|
try {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@@ -356,7 +360,7 @@ public class BMPImageReaderTest extends ImageReaderAbstractTest<BMPImageReader>
|
|||||||
}
|
}
|
||||||
IIOMetadata jreMetadata = jreReader.getImageMetadata(0);
|
IIOMetadata jreMetadata = jreReader.getImageMetadata(0);
|
||||||
|
|
||||||
assertEquals(true, metadata.isStandardMetadataFormatSupported());
|
assertTrue(metadata.isStandardMetadataFormatSupported());
|
||||||
assertEquals(jreMetadata.getNativeMetadataFormatName(), metadata.getNativeMetadataFormatName());
|
assertEquals(jreMetadata.getNativeMetadataFormatName(), metadata.getNativeMetadataFormatName());
|
||||||
assertArrayEquals(jreMetadata.getExtraMetadataFormatNames(), metadata.getExtraMetadataFormatNames());
|
assertArrayEquals(jreMetadata.getExtraMetadataFormatNames(), metadata.getExtraMetadataFormatNames());
|
||||||
|
|
||||||
@@ -379,7 +383,7 @@ public class BMPImageReaderTest extends ImageReaderAbstractTest<BMPImageReader>
|
|||||||
new XMLSerializer(expected, "UTF-8").serialize(expectedTree, false);
|
new XMLSerializer(expected, "UTF-8").serialize(expectedTree, false);
|
||||||
new XMLSerializer(actual, "UTF-8").serialize(actualTree, false);
|
new XMLSerializer(actual, "UTF-8").serialize(actualTree, false);
|
||||||
|
|
||||||
assertEquals(e.getMessage(), new String(expected.toByteArray(), "UTF-8"), new String(actual.toByteArray(), "UTF-8"));
|
assertEquals(e.getMessage(), new String(expected.toByteArray(), StandardCharsets.UTF_8), new String(actual.toByteArray(), StandardCharsets.UTF_8));
|
||||||
|
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.imageio.util.ImageWriterAbstractTest;
|
||||||
|
|
||||||
|
import javax.imageio.spi.ImageWriterSpi;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.awt.image.RenderedImage;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BMPImageWriterTest.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by : harald.kuhr$
|
||||||
|
* @version : BMPImageWriterTest.java,v 1.0 25/06/2020 harald.kuhr Exp$
|
||||||
|
*/
|
||||||
|
public class BMPImageWriterTest extends ImageWriterAbstractTest<BMPImageWriter> {
|
||||||
|
@Override
|
||||||
|
protected ImageWriterSpi createProvider() {
|
||||||
|
return new BMPImageWriterSpi();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<? extends RenderedImage> getTestData() {
|
||||||
|
return Collections.singletonList(
|
||||||
|
new BufferedImage(10, 10, BufferedImage.TYPE_4BYTE_ABGR)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,6 +31,7 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.bmp;
|
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
||||||
|
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -53,6 +54,12 @@ import static org.junit.Assert.*;
|
|||||||
* @version $Id: CURImageReaderTest.java,v 1.0 Apr 1, 2008 10:39:17 PM haraldk Exp$
|
* @version $Id: CURImageReaderTest.java,v 1.0 Apr 1, 2008 10:39:17 PM haraldk Exp$
|
||||||
*/
|
*/
|
||||||
public class CURImageReaderTest extends ImageReaderAbstractTest<CURImageReader> {
|
public class CURImageReaderTest extends ImageReaderAbstractTest<CURImageReader> {
|
||||||
|
@Override
|
||||||
|
protected ImageReaderSpi createProvider() {
|
||||||
|
return new CURImageReaderSpi();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected List<TestData> getTestData() {
|
protected List<TestData> getTestData() {
|
||||||
return Arrays.asList(
|
return Arrays.asList(
|
||||||
new TestData(getClassLoaderResource("/cur/hand.cur"), new Dimension(32, 32)),
|
new TestData(getClassLoaderResource("/cur/hand.cur"), new Dimension(32, 32)),
|
||||||
@@ -60,27 +67,17 @@ public class CURImageReaderTest extends ImageReaderAbstractTest<CURImageReader>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ImageReaderSpi createProvider() {
|
|
||||||
return new CURImageReaderSpi();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected CURImageReader createReader() {
|
|
||||||
return new CURImageReader();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Class<CURImageReader> getReaderClass() {
|
|
||||||
return CURImageReader.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected List<String> getFormatNames() {
|
protected List<String> getFormatNames() {
|
||||||
return Collections.singletonList("cur");
|
return Collections.singletonList("cur");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected List<String> getSuffixes() {
|
protected List<String> getSuffixes() {
|
||||||
return Collections.singletonList("cur");
|
return Collections.singletonList("cur");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected List<String> getMIMETypes() {
|
protected List<String> getMIMETypes() {
|
||||||
return Arrays.asList("image/vnd.microsoft.cursor", "image/cursor", "image/x-cursor");
|
return Arrays.asList("image/vnd.microsoft.cursor", "image/cursor", "image/x-cursor");
|
||||||
}
|
}
|
||||||
@@ -99,7 +96,7 @@ public class CURImageReaderTest extends ImageReaderAbstractTest<CURImageReader>
|
|||||||
assertNotNull("Hotspot for cursor not present", hotspot);
|
assertNotNull("Hotspot for cursor not present", hotspot);
|
||||||
|
|
||||||
// Image weirdness
|
// Image weirdness
|
||||||
assertTrue("Hotspot for cursor undefined (java.awt.Image.UndefinedProperty)", Image.UndefinedProperty != hotspot);
|
assertNotSame("Hotspot for cursor undefined (java.awt.Image.UndefinedProperty)", Image.UndefinedProperty, hotspot);
|
||||||
|
|
||||||
assertTrue(String.format("Hotspot not a java.awt.Point: %s", hotspot.getClass()), hotspot instanceof Point);
|
assertTrue(String.format("Hotspot not a java.awt.Point: %s", hotspot.getClass()), hotspot instanceof Point);
|
||||||
assertEquals(pExpected, hotspot);
|
assertEquals(pExpected, hotspot);
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.bmp;
|
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
||||||
|
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -49,6 +50,12 @@ import java.util.List;
|
|||||||
* @version $Id: ICOImageReaderTest.java,v 1.0 Apr 1, 2008 10:39:17 PM haraldk Exp$
|
* @version $Id: ICOImageReaderTest.java,v 1.0 Apr 1, 2008 10:39:17 PM haraldk Exp$
|
||||||
*/
|
*/
|
||||||
public class ICOImageReaderTest extends ImageReaderAbstractTest<ICOImageReader> {
|
public class ICOImageReaderTest extends ImageReaderAbstractTest<ICOImageReader> {
|
||||||
|
@Override
|
||||||
|
protected ImageReaderSpi createProvider() {
|
||||||
|
return new ICOImageReaderSpi();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected List<TestData> getTestData() {
|
protected List<TestData> getTestData() {
|
||||||
return Arrays.asList(
|
return Arrays.asList(
|
||||||
new TestData(
|
new TestData(
|
||||||
@@ -75,27 +82,17 @@ public class ICOImageReaderTest extends ImageReaderAbstractTest<ICOImageReader>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ImageReaderSpi createProvider() {
|
|
||||||
return new ICOImageReaderSpi();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ICOImageReader createReader() {
|
|
||||||
return new ICOImageReader();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Class<ICOImageReader> getReaderClass() {
|
|
||||||
return ICOImageReader.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected List<String> getFormatNames() {
|
protected List<String> getFormatNames() {
|
||||||
return Collections.singletonList("ico");
|
return Collections.singletonList("ico");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected List<String> getSuffixes() {
|
protected List<String> getSuffixes() {
|
||||||
return Collections.singletonList("ico");
|
return Collections.singletonList("ico");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected List<String> getMIMETypes() {
|
protected List<String> getMIMETypes() {
|
||||||
return Arrays.asList("image/vnd.microsoft.icon", "image/ico", "image/x-icon");
|
return Arrays.asList("image/vnd.microsoft.icon", "image/ico", "image/x-icon");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.imageio.util.ImageWriterAbstractTest;
|
||||||
|
|
||||||
|
import javax.imageio.spi.ImageWriterSpi;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.awt.image.RenderedImage;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ICOImageWriterTest.
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by : harald.kuhr$
|
||||||
|
* @version : ICOImageWriterTest.java,v 1.0 25/06/2020 harald.kuhr Exp$
|
||||||
|
*/
|
||||||
|
public class ICOImageWriterTest extends ImageWriterAbstractTest<ICOImageWriter> {
|
||||||
|
@Override
|
||||||
|
protected ImageWriterSpi createProvider() {
|
||||||
|
return new ICOImageWriterSpi();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<? extends RenderedImage> getTestData() {
|
||||||
|
return Arrays.asList(
|
||||||
|
new BufferedImage(8, 8, BufferedImage.TYPE_4BYTE_ABGR),
|
||||||
|
new BufferedImage(16, 16, BufferedImage.TYPE_4BYTE_ABGR),
|
||||||
|
new BufferedImage(32, 32, BufferedImage.TYPE_4BYTE_ABGR),
|
||||||
|
new BufferedImage(64, 64, BufferedImage.TYPE_4BYTE_ABGR),
|
||||||
|
new BufferedImage(128, 128, BufferedImage.TYPE_4BYTE_ABGR)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.5</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>
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio-core</artifactId>
|
<artifactId>imageio-core</artifactId>
|
||||||
<type>test-jar</type>
|
<type>test-jar</type>
|
||||||
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
|||||||
@@ -107,8 +107,8 @@ final class AdobePathSegment {
|
|||||||
case OPEN_SUBPATH_BEZIER_LINKED:
|
case OPEN_SUBPATH_BEZIER_LINKED:
|
||||||
case OPEN_SUBPATH_BEZIER_UNLINKED:
|
case OPEN_SUBPATH_BEZIER_UNLINKED:
|
||||||
isTrue(
|
isTrue(
|
||||||
cppx >= 0 && cppx <= 1 && cppy >= 0 && cppy <= 1,
|
cppx >= -16 && cppx <= 16 && cppy >= -16 && cppy <= 16,
|
||||||
String.format("Expected point in range [0...1]: (%f, %f)", cppx ,cppy)
|
String.format("Expected point in range [-16...16]: (%f, %f)", cppx ,cppy)
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case PATH_FILL_RULE_RECORD:
|
case PATH_FILL_RULE_RECORD:
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ import java.awt.image.BufferedImage;
|
|||||||
import java.awt.image.RenderedImage;
|
import java.awt.image.RenderedImage;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.SequenceInputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -131,7 +133,13 @@ public final class Paths {
|
|||||||
List<JPEGSegment> photoshop = JPEGSegmentUtil.readSegments(stream, segmentIdentifiers);
|
List<JPEGSegment> photoshop = JPEGSegmentUtil.readSegments(stream, segmentIdentifiers);
|
||||||
|
|
||||||
if (!photoshop.isEmpty()) {
|
if (!photoshop.isEmpty()) {
|
||||||
return readPathFromPhotoshopResources(new MemoryCacheImageInputStream(photoshop.get(0).data()));
|
InputStream data = null;
|
||||||
|
|
||||||
|
for (JPEGSegment ps : photoshop) {
|
||||||
|
data = data == null ? ps.data() : new SequenceInputStream(data, ps.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
return readPathFromPhotoshopResources(new MemoryCacheImageInputStream(data));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (magic >>> 16 == TIFF.BYTE_ORDER_MARK_BIG_ENDIAN && (magic & 0xffff) == TIFF.TIFF_MAGIC
|
else if (magic >>> 16 == TIFF.BYTE_ORDER_MARK_BIG_ENDIAN && (magic & 0xffff) == TIFF.TIFF_MAGIC
|
||||||
@@ -350,10 +358,10 @@ public final class Paths {
|
|||||||
IIOMetadataNode unknown = new IIOMetadataNode("unknown");
|
IIOMetadataNode unknown = new IIOMetadataNode("unknown");
|
||||||
unknown.setAttribute("MarkerTag", Integer.toString(JPEG.APP13 & 0xFF));
|
unknown.setAttribute("MarkerTag", Integer.toString(JPEG.APP13 & 0xFF));
|
||||||
|
|
||||||
byte[] identfier = "Photoshop 3.0".getBytes(StandardCharsets.US_ASCII);
|
byte[] identifier = "Photoshop 3.0".getBytes(StandardCharsets.US_ASCII);
|
||||||
byte[] data = new byte[identfier.length + 1 + pathResource.length];
|
byte[] data = new byte[identifier.length + 1 + pathResource.length];
|
||||||
System.arraycopy(identfier, 0, data, 0, identfier.length);
|
System.arraycopy(identifier, 0, data, 0, identifier.length);
|
||||||
System.arraycopy(pathResource, 0, data, identfier.length + 1, pathResource.length);
|
System.arraycopy(pathResource, 0, data, identifier.length + 1, pathResource.length);
|
||||||
|
|
||||||
unknown.setUserObject(data);
|
unknown.setUserObject(data);
|
||||||
|
|
||||||
|
|||||||
@@ -113,8 +113,13 @@ public class AdobePathSegmentTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void testCreateOpenLinkedRecordNegative() {
|
public void testCreateOpenLinkedRecordOutOfRangeNegative() {
|
||||||
new AdobePathSegment(AdobePathSegment.OPEN_SUBPATH_BEZIER_LINKED, -.5, -.5, 0, 0, 1, 1);
|
new AdobePathSegment(AdobePathSegment.OPEN_SUBPATH_BEZIER_LINKED, -16.1, -16.1, 0, 0, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testCreateOpenLinkedRecordOutOfRangePositive() {
|
||||||
|
new AdobePathSegment(AdobePathSegment.OPEN_SUBPATH_BEZIER_LINKED, 16.1, 16.1, 0, 0, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -138,8 +143,13 @@ public class AdobePathSegmentTest {
|
|||||||
|
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void testCreateOpenUnlinkedRecordNegative() {
|
public void testCreateOpenUnlinkedRecordOutOfRangeNegative() {
|
||||||
new AdobePathSegment(AdobePathSegment.OPEN_SUBPATH_BEZIER_UNLINKED, -.5, -.5, 0, 0, 1, 1);
|
new AdobePathSegment(AdobePathSegment.OPEN_SUBPATH_BEZIER_UNLINKED, -16.5, 0, 0, 0, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testCreateOpenUnlinkedRecorOutOfRangePositive() {
|
||||||
|
new AdobePathSegment(AdobePathSegment.OPEN_SUBPATH_BEZIER_UNLINKED, 0, -17, 0, 0, 16.5, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Closed subpath
|
/// Closed subpath
|
||||||
@@ -164,8 +174,13 @@ public class AdobePathSegmentTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void testCreateClosedLinkedRecordNegative() {
|
public void testCreateClosedLinkedRecordOutOfRangeNegative() {
|
||||||
new AdobePathSegment(AdobePathSegment.CLOSED_SUBPATH_BEZIER_LINKED, -.5, -.5, 0, 0, 1, 1);
|
new AdobePathSegment(AdobePathSegment.CLOSED_SUBPATH_BEZIER_LINKED, -16.5, -.5, 0, 0, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testCreateClosedLinkedRecordOutOfRangePositive() {
|
||||||
|
new AdobePathSegment(AdobePathSegment.CLOSED_SUBPATH_BEZIER_LINKED, .5, 16.5, 0, 0, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -189,8 +204,13 @@ public class AdobePathSegmentTest {
|
|||||||
|
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void testCreateClosedUnlinkedRecordNegative() {
|
public void testCreateClosedUnlinkedRecordOutOfRangeNegative() {
|
||||||
new AdobePathSegment(AdobePathSegment.CLOSED_SUBPATH_BEZIER_UNLINKED, -.5, -.5, 0, 0, 1, 1);
|
new AdobePathSegment(AdobePathSegment.CLOSED_SUBPATH_BEZIER_UNLINKED, -.5, -16.5, 0, 0, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void testCreateClosedUnlinkedRecordOutOfRangePositive() {
|
||||||
|
new AdobePathSegment(AdobePathSegment.CLOSED_SUBPATH_BEZIER_UNLINKED, 16.5, .5, 0, 0, 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.5</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>
|
||||||
|
|||||||
@@ -314,12 +314,12 @@ public abstract class ImageReaderBase extends ImageReader {
|
|||||||
|
|
||||||
long dimension = (long) destWidth * destHeight;
|
long dimension = (long) destWidth * destHeight;
|
||||||
if (dimension > Integer.MAX_VALUE) {
|
if (dimension > Integer.MAX_VALUE) {
|
||||||
throw new IllegalArgumentException(String.format("destination width * height > Integer.MAX_VALUE: %d", dimension));
|
throw new IIOException(String.format("destination width * height > Integer.MAX_VALUE: %d", dimension));
|
||||||
}
|
}
|
||||||
|
|
||||||
long size = dimension * imageType.getSampleModel().getNumDataElements();
|
long size = dimension * imageType.getSampleModel().getNumDataElements();
|
||||||
if (size > Integer.MAX_VALUE) {
|
if (size > Integer.MAX_VALUE) {
|
||||||
throw new IllegalArgumentException(String.format("destination width * height * samplesPerPixel > Integer.MAX_VALUE: %d", size));
|
throw new IIOException(String.format("destination width * height * samplesPerPixel > Integer.MAX_VALUE: %d", size));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new image based on the type specifier
|
// Create a new image based on the type specifier
|
||||||
@@ -440,6 +440,7 @@ public abstract class ImageReaderBase extends ImageReader {
|
|||||||
static final String ZOOM_IN = "zoom-in";
|
static final String ZOOM_IN = "zoom-in";
|
||||||
static final String ZOOM_OUT = "zoom-out";
|
static final String ZOOM_OUT = "zoom-out";
|
||||||
static final String ZOOM_ACTUAL = "zoom-actual";
|
static final String ZOOM_ACTUAL = "zoom-actual";
|
||||||
|
static final String ZOOM_FIT = "zoom-fit";
|
||||||
|
|
||||||
private BufferedImage image;
|
private BufferedImage image;
|
||||||
|
|
||||||
@@ -515,9 +516,20 @@ public abstract class ImageReaderBase extends ImageReader {
|
|||||||
|
|
||||||
private void setupActions() {
|
private void setupActions() {
|
||||||
// Mac weirdness... VK_MINUS/VK_PLUS seems to map to english key map always...
|
// Mac weirdness... VK_MINUS/VK_PLUS seems to map to english key map always...
|
||||||
bindAction(new ZoomAction("Zoom in", 2), ZOOM_IN, KeyStroke.getKeyStroke('+'), KeyStroke.getKeyStroke(KeyEvent.VK_ADD, 0));
|
bindAction(new ZoomAction("Zoom in", 2), ZOOM_IN,
|
||||||
bindAction(new ZoomAction("Zoom out", .5), ZOOM_OUT, KeyStroke.getKeyStroke('-'), KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, 0));
|
KeyStroke.getKeyStroke('+'),
|
||||||
bindAction(new ZoomAction("Zoom actual"), ZOOM_ACTUAL, KeyStroke.getKeyStroke('0'), KeyStroke.getKeyStroke(KeyEvent.VK_0, 0));
|
KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
|
||||||
|
KeyStroke.getKeyStroke(KeyEvent.VK_ADD, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
|
||||||
|
bindAction(new ZoomAction("Zoom out", .5), ZOOM_OUT,
|
||||||
|
KeyStroke.getKeyStroke('-'),
|
||||||
|
KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
|
||||||
|
KeyStroke.getKeyStroke(KeyEvent.VK_SUBTRACT, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
|
||||||
|
bindAction(new ZoomAction("Zoom actual"), ZOOM_ACTUAL,
|
||||||
|
KeyStroke.getKeyStroke('0'),
|
||||||
|
KeyStroke.getKeyStroke(KeyEvent.VK_0, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
|
||||||
|
bindAction(new ZoomToFitAction("Zoom fit"), ZOOM_FIT,
|
||||||
|
KeyStroke.getKeyStroke('9'),
|
||||||
|
KeyStroke.getKeyStroke(KeyEvent.VK_9, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
|
||||||
|
|
||||||
bindAction(TransferHandler.getCopyAction(), (String) TransferHandler.getCopyAction().getValue(Action.NAME), KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
|
bindAction(TransferHandler.getCopyAction(), (String) TransferHandler.getCopyAction().getValue(Action.NAME), KeyStroke.getKeyStroke(KeyEvent.VK_C, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
|
||||||
bindAction(TransferHandler.getPasteAction(), (String) TransferHandler.getPasteAction().getValue(Action.NAME), KeyStroke.getKeyStroke(KeyEvent.VK_V, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
|
bindAction(TransferHandler.getPasteAction(), (String) TransferHandler.getPasteAction().getValue(Action.NAME), KeyStroke.getKeyStroke(KeyEvent.VK_V, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
|
||||||
@@ -534,6 +546,7 @@ public abstract class ImageReaderBase extends ImageReader {
|
|||||||
private JPopupMenu createPopupMenu() {
|
private JPopupMenu createPopupMenu() {
|
||||||
JPopupMenu popup = new JPopupMenu();
|
JPopupMenu popup = new JPopupMenu();
|
||||||
|
|
||||||
|
popup.add(getActionMap().get(ZOOM_FIT));
|
||||||
popup.add(getActionMap().get(ZOOM_ACTUAL));
|
popup.add(getActionMap().get(ZOOM_ACTUAL));
|
||||||
popup.add(getActionMap().get(ZOOM_IN));
|
popup.add(getActionMap().get(ZOOM_IN));
|
||||||
popup.add(getActionMap().get(ZOOM_OUT));
|
popup.add(getActionMap().get(ZOOM_OUT));
|
||||||
@@ -554,7 +567,7 @@ public abstract class ImageReaderBase extends ImageReader {
|
|||||||
addCheckBoxItem(new ChangeBackgroundAction("Dark", Color.DARK_GRAY), background, group);
|
addCheckBoxItem(new ChangeBackgroundAction("Dark", Color.DARK_GRAY), background, group);
|
||||||
addCheckBoxItem(new ChangeBackgroundAction("Black", Color.BLACK), background, group);
|
addCheckBoxItem(new ChangeBackgroundAction("Black", Color.BLACK), background, group);
|
||||||
background.addSeparator();
|
background.addSeparator();
|
||||||
ChooseBackgroundAction chooseBackgroundAction = new ChooseBackgroundAction("Choose...", defaultBG != null ? defaultBG : Color.BLUE);
|
ChooseBackgroundAction chooseBackgroundAction = new ChooseBackgroundAction("Choose...", defaultBG != null ? defaultBG : new Color(0xFF6600));
|
||||||
chooseBackgroundAction.putValue(Action.SELECTED_KEY, backgroundPaint == defaultBG);
|
chooseBackgroundAction.putValue(Action.SELECTED_KEY, backgroundPaint == defaultBG);
|
||||||
addCheckBoxItem(chooseBackgroundAction, background, group);
|
addCheckBoxItem(chooseBackgroundAction, background, group);
|
||||||
|
|
||||||
@@ -668,14 +681,41 @@ public abstract class ImageReaderBase extends ImageReader {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Icon current = getIcon();
|
Icon current = getIcon();
|
||||||
int w = (int) Math.max(Math.min(current.getIconWidth() * zoomFactor, image.getWidth() * 16), image.getWidth() / 16);
|
int w = Math.max(Math.min((int) (current.getIconWidth() * zoomFactor), image.getWidth() * 16), image.getWidth() / 16);
|
||||||
int h = (int) Math.max(Math.min(current.getIconHeight() * zoomFactor, image.getHeight() * 16), image.getHeight() / 16);
|
int h = Math.max(Math.min((int) (current.getIconHeight() * zoomFactor), image.getHeight() * 16), image.getHeight() / 16);
|
||||||
|
|
||||||
setIcon(new BufferedImageIcon(image, Math.max(w, 2), Math.max(h, 2), w > image.getWidth() || h > image.getHeight()));
|
setIcon(new BufferedImageIcon(image, Math.max(w, 2), Math.max(h, 2), w > image.getWidth() || h > image.getHeight()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ZoomToFitAction extends ZoomAction {
|
||||||
|
public ZoomToFitAction(final String name) {
|
||||||
|
super(name, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void actionPerformed(final ActionEvent e) {
|
||||||
|
JComponent source = (JComponent) e.getSource();
|
||||||
|
|
||||||
|
if (source instanceof JMenuItem) {
|
||||||
|
JPopupMenu menu = (JPopupMenu) SwingUtilities.getAncestorOfClass(JPopupMenu.class, source);
|
||||||
|
source = (JComponent) menu.getInvoker();
|
||||||
|
}
|
||||||
|
|
||||||
|
Container container = SwingUtilities.getAncestorOfClass(JViewport.class, source);
|
||||||
|
|
||||||
|
double ratioX = container.getWidth() / (double) image.getWidth();
|
||||||
|
double ratioY = container.getHeight() / (double) image.getHeight();
|
||||||
|
|
||||||
|
double zoomFactor = Math.min(ratioX, ratioY);
|
||||||
|
|
||||||
|
int w = Math.max(Math.min((int) (image.getWidth() * zoomFactor), image.getWidth() * 16), image.getWidth() / 16);
|
||||||
|
int h = Math.max(Math.min((int) (image.getHeight() * zoomFactor), image.getHeight() * 16), image.getHeight() / 16);
|
||||||
|
|
||||||
|
setIcon(new BufferedImageIcon(image, w, h, zoomFactor > 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static class ImageTransferable implements Transferable {
|
private static class ImageTransferable implements Transferable {
|
||||||
private final BufferedImage image;
|
private final BufferedImage image;
|
||||||
|
|
||||||
@@ -694,7 +734,7 @@ public abstract class ImageReaderBase extends ImageReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getTransferData(final DataFlavor flavor) throws UnsupportedFlavorException, IOException {
|
public Object getTransferData(final DataFlavor flavor) throws UnsupportedFlavorException {
|
||||||
if (isDataFlavorSupported(flavor)) {
|
if (isDataFlavorSupported(flavor)) {
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,8 +57,10 @@ public final class BufferedImageInputStream extends ImageInputStreamImpl impleme
|
|||||||
|
|
||||||
private ImageInputStream stream;
|
private ImageInputStream stream;
|
||||||
|
|
||||||
private ByteBuffer buffer;
|
private ByteBuffer buffer;
|
||||||
private ByteBuffer integralCache = ByteBuffer.allocate(8);
|
|
||||||
|
private final ByteBuffer integralCache = ByteBuffer.allocate(8);
|
||||||
|
private final byte[] integralCacheArray = integralCache.array();
|
||||||
|
|
||||||
public BufferedImageInputStream(final ImageInputStream pStream) throws IOException {
|
public BufferedImageInputStream(final ImageInputStream pStream) throws IOException {
|
||||||
this(pStream, DEFAULT_BUFFER_SIZE);
|
this(pStream, DEFAULT_BUFFER_SIZE);
|
||||||
@@ -97,10 +99,10 @@ public final class BufferedImageInputStream extends ImageInputStreamImpl impleme
|
|||||||
|
|
||||||
if (!buffer.hasRemaining()) {
|
if (!buffer.hasRemaining()) {
|
||||||
fillBuffer();
|
fillBuffer();
|
||||||
}
|
|
||||||
|
|
||||||
if (!buffer.hasRemaining()) {
|
if (!buffer.hasRemaining()) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bitOffset = 0;
|
bitOffset = 0;
|
||||||
@@ -172,21 +174,21 @@ public final class BufferedImageInputStream extends ImageInputStreamImpl impleme
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public short readShort() throws IOException {
|
public short readShort() throws IOException {
|
||||||
readFully(integralCache.array(), 0, 2);
|
readFully(integralCacheArray, 0, 2);
|
||||||
|
|
||||||
return integralCache.getShort(0);
|
return integralCache.getShort(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int readInt() throws IOException {
|
public int readInt() throws IOException {
|
||||||
readFully(integralCache.array(), 0, 4);
|
readFully(integralCacheArray, 0, 4);
|
||||||
|
|
||||||
return integralCache.getInt(0);
|
return integralCache.getInt(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long readLong() throws IOException {
|
public long readLong() throws IOException {
|
||||||
readFully(integralCache.array(), 0, 8);
|
readFully(integralCacheArray, 0, 8);
|
||||||
|
|
||||||
return integralCache.getLong(0);
|
return integralCache.getLong(0);
|
||||||
}
|
}
|
||||||
@@ -253,6 +255,7 @@ public final class BufferedImageInputStream extends ImageInputStreamImpl impleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
int val = buffer.get() & 0xff;
|
int val = buffer.get() & 0xff;
|
||||||
|
streamPos++;
|
||||||
|
|
||||||
accum <<= 8;
|
accum <<= 8;
|
||||||
accum |= val;
|
accum |= val;
|
||||||
@@ -262,9 +265,7 @@ public final class BufferedImageInputStream extends ImageInputStreamImpl impleme
|
|||||||
// Move byte position back if in the middle of a byte
|
// Move byte position back if in the middle of a byte
|
||||||
if (newBitOffset != 0) {
|
if (newBitOffset != 0) {
|
||||||
buffer.position(buffer.position() - 1);
|
buffer.position(buffer.position() - 1);
|
||||||
}
|
streamPos--;
|
||||||
else {
|
|
||||||
streamPos++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.bitOffset = newBitOffset;
|
this.bitOffset = newBitOffset;
|
||||||
@@ -279,26 +280,26 @@ public final class BufferedImageInputStream extends ImageInputStreamImpl impleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void seek(long pPosition) throws IOException {
|
public void seek(long position) throws IOException {
|
||||||
checkClosed();
|
checkClosed();
|
||||||
bitOffset = 0;
|
bitOffset = 0;
|
||||||
|
|
||||||
if (streamPos == pPosition) {
|
if (streamPos == position) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optimized to not invalidate buffer if new position is within current buffer
|
// Optimized to not invalidate buffer if new position is within current buffer
|
||||||
long newBufferPos = buffer.position() + pPosition - streamPos;
|
long newBufferPos = buffer.position() + position - streamPos;
|
||||||
if (newBufferPos >= 0 && newBufferPos <= buffer.limit()) {
|
if (newBufferPos >= 0 && newBufferPos <= buffer.limit()) {
|
||||||
buffer.position((int) newBufferPos);
|
buffer.position((int) newBufferPos);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Will invalidate buffer
|
// Will invalidate buffer
|
||||||
buffer.limit(0);
|
buffer.limit(0);
|
||||||
stream.seek(pPosition);
|
stream.seek(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
streamPos = pPosition;
|
streamPos = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -330,7 +331,9 @@ public final class BufferedImageInputStream extends ImageInputStreamImpl impleme
|
|||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
if (stream != null) {
|
if (stream != null) {
|
||||||
//stream.close();
|
// TODO: FixMe: Need to close underlying stream here!
|
||||||
|
// For call sites that relies on not closing, we should instead not close the buffered stream.
|
||||||
|
// stream.close();
|
||||||
stream = null;
|
stream = null;
|
||||||
buffer = null;
|
buffer = null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,10 +30,11 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.stream;
|
package com.twelvemonkeys.imageio.stream;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.imageio.spi.ProviderInfo;
|
||||||
|
|
||||||
import javax.imageio.spi.ImageInputStreamSpi;
|
import javax.imageio.spi.ImageInputStreamSpi;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,10 +48,14 @@ import java.util.Locale;
|
|||||||
public class ByteArrayImageInputStreamSpi extends ImageInputStreamSpi {
|
public class ByteArrayImageInputStreamSpi extends ImageInputStreamSpi {
|
||||||
|
|
||||||
public ByteArrayImageInputStreamSpi() {
|
public ByteArrayImageInputStreamSpi() {
|
||||||
super("TwelveMonkeys", "1.0 BETA", byte[].class);
|
this(new StreamProviderInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImageInputStream createInputStreamInstance(Object pInput, boolean pUseCache, File pCacheDir) throws IOException {
|
private ByteArrayImageInputStreamSpi(ProviderInfo providerInfo) {
|
||||||
|
super(providerInfo.getVendorName(), providerInfo.getVersion(), byte[].class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageInputStream createInputStreamInstance(Object pInput, boolean pUseCache, File pCacheDir) {
|
||||||
if (pInput instanceof byte[]) {
|
if (pInput instanceof byte[]) {
|
||||||
return new ByteArrayImageInputStream((byte[]) pInput);
|
return new ByteArrayImageInputStream((byte[]) pInput);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.twelvemonkeys.imageio.stream;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.imageio.spi.ProviderInfo;
|
||||||
|
|
||||||
|
final class StreamProviderInfo extends ProviderInfo {
|
||||||
|
StreamProviderInfo() {
|
||||||
|
super(StreamProviderInfo.class.getPackage());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,6 +30,8 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.stream;
|
package com.twelvemonkeys.imageio.stream;
|
||||||
|
|
||||||
|
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.FileImageInputStream;
|
||||||
@@ -53,7 +55,11 @@ import java.util.Locale;
|
|||||||
// TODO: URI instead of URL?
|
// TODO: URI instead of URL?
|
||||||
public class URLImageInputStreamSpi extends ImageInputStreamSpi {
|
public class URLImageInputStreamSpi extends ImageInputStreamSpi {
|
||||||
public URLImageInputStreamSpi() {
|
public URLImageInputStreamSpi() {
|
||||||
super("TwelveMonkeys", "1.0 BETA", URL.class);
|
this(new StreamProviderInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
private URLImageInputStreamSpi(ProviderInfo providerInfo) {
|
||||||
|
super(providerInfo.getVendorName(), providerInfo.getVersion(), URL.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Create a URI or URLImageInputStream class, with a getUR[I|L] method, to allow for multiple file formats
|
// TODO: Create a URI or URLImageInputStream class, with a getUR[I|L] method, to allow for multiple file formats
|
||||||
@@ -108,6 +114,11 @@ public class URLImageInputStreamSpi extends ImageInputStreamSpi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canUseCacheFile() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public String getDescription(final Locale pLocale) {
|
public String getDescription(final Locale pLocale) {
|
||||||
return "Service provider that instantiates an ImageInputStream from a URL";
|
return "Service provider that instantiates an ImageInputStream from a URL";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -291,4 +291,21 @@ public final class IIOUtil {
|
|||||||
System.arraycopy(srcRow, srcPos + x, destRow, destPos + x / samplePeriod, pixelStride);
|
System.arraycopy(srcRow, srcPos + x, destRow, destPos + x / samplePeriod, pixelStride);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void subsampleRow(float[] srcRow, int srcPos, int srcWidth,
|
||||||
|
float[] destRow, int destPos,
|
||||||
|
int samplesPerPixel, int bitsPerSample, int samplePeriod) {
|
||||||
|
Validate.isTrue(samplePeriod > 1, "samplePeriod must be > 1"); // Period == 1 could be a no-op...
|
||||||
|
Validate.isTrue(bitsPerSample > 0 && bitsPerSample <= 32 && (bitsPerSample == 1 || bitsPerSample % 2 == 0),
|
||||||
|
"bitsPerSample must be > 0 and <= 32 and a power of 2");
|
||||||
|
Validate.isTrue(samplesPerPixel > 0, "samplesPerPixel must be > 0");
|
||||||
|
Validate.isTrue(samplesPerPixel * bitsPerSample <= 32 || samplesPerPixel * bitsPerSample % 32 == 0,
|
||||||
|
"samplesPerPixel * bitsPerSample must be < 32 or a multiple of 32 ");
|
||||||
|
|
||||||
|
int pixelStride = bitsPerSample * samplesPerPixel / 32;
|
||||||
|
for (int x = 0; x < srcWidth * pixelStride; x += samplePeriod * pixelStride) {
|
||||||
|
// System.arraycopy should be intrinsic, but consider using direct array access for pixelStride == 1
|
||||||
|
System.arraycopy(srcRow, srcPos + x, destRow, destPos + x / samplePeriod, pixelStride);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -30,11 +30,11 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio;
|
package com.twelvemonkeys.imageio;
|
||||||
|
|
||||||
import org.junit.Test;
|
import static java.util.Collections.singleton;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
|
||||||
import javax.imageio.ImageReadParam;
|
|
||||||
import javax.imageio.ImageTypeSpecifier;
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.color.ColorSpace;
|
import java.awt.color.ColorSpace;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
@@ -44,8 +44,11 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static java.util.Collections.singleton;
|
import javax.imageio.IIOException;
|
||||||
import static org.junit.Assert.*;
|
import javax.imageio.ImageReadParam;
|
||||||
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ImageReaderBaseTest
|
* ImageReaderBaseTest
|
||||||
@@ -212,19 +215,19 @@ public class ImageReaderBaseTest {
|
|||||||
assertEquals(TYPES.get(0).getBufferedImageType(), destination.getType());
|
assertEquals(TYPES.get(0).getBufferedImageType(), destination.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IIOException.class)
|
||||||
public void testGetDestinationParamDestinationExceedsIntegerMax() throws IIOException {
|
public void testGetDestinationParamDestinationExceedsIntegerMax() throws IIOException {
|
||||||
ImageReadParam param = new ImageReadParam();
|
ImageReadParam param = new ImageReadParam();
|
||||||
param.setSourceRegion(new Rectangle(3 * Short.MAX_VALUE, 2 * Short.MAX_VALUE)); // 6 442 057 734 pixels
|
param.setSourceRegion(new Rectangle(3 * Short.MAX_VALUE, 2 * Short.MAX_VALUE)); // 6 442 057 734 pixels
|
||||||
ImageReaderBase.getDestination(param, TYPES.iterator(), 6 * Short.MAX_VALUE, 4 * Short.MAX_VALUE); // 25 768 230 936 pixels
|
ImageReaderBase.getDestination(param, TYPES.iterator(), 6 * Short.MAX_VALUE, 4 * Short.MAX_VALUE); // 25 768 230 936 pixels
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IIOException.class)
|
||||||
public void testGetDestinationDimensionExceedsIntegerMax() throws IIOException {
|
public void testGetDestinationDimensionExceedsIntegerMax() throws IIOException {
|
||||||
ImageReaderBase.getDestination(null, TYPES.iterator(), 3 * Short.MAX_VALUE, 2 * Short.MAX_VALUE); // 6 442 057 734 pixels
|
ImageReaderBase.getDestination(null, TYPES.iterator(), 3 * Short.MAX_VALUE, 2 * Short.MAX_VALUE); // 6 442 057 734 pixels
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IIOException.class)
|
||||||
public void testGetDestinationStorageExceedsIntegerMax() throws IIOException {
|
public void testGetDestinationStorageExceedsIntegerMax() throws IIOException {
|
||||||
Set<ImageTypeSpecifier> byteTypes = singleton(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR));
|
Set<ImageTypeSpecifier> byteTypes = singleton(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR));
|
||||||
ImageReaderBase.getDestination(null, byteTypes.iterator(), Short.MAX_VALUE, Short.MAX_VALUE); // 1 073 676 289 pixels
|
ImageReaderBase.getDestination(null, byteTypes.iterator(), Short.MAX_VALUE, Short.MAX_VALUE); // 1 073 676 289 pixels
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ import org.junit.Test;
|
|||||||
|
|
||||||
import java.awt.image.*;
|
import java.awt.image.*;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
public class DiscreteAlphaIndexColorModelTest {
|
public class DiscreteAlphaIndexColorModelTest {
|
||||||
@@ -162,7 +164,7 @@ public class DiscreteAlphaIndexColorModelTest {
|
|||||||
assertEquals(2, sampleModel.getHeight());
|
assertEquals(2, sampleModel.getHeight());
|
||||||
|
|
||||||
assertTrue(colorModel.isCompatibleSampleModel(sampleModel));
|
assertTrue(colorModel.isCompatibleSampleModel(sampleModel));
|
||||||
assertThat(sampleModel, CoreMatchers.is(PixelInterleavedSampleModel.class));
|
assertThat(sampleModel, instanceOf(PixelInterleavedSampleModel.class));
|
||||||
assertThat(sampleModel.getDataType(), CoreMatchers.equalTo(DataBuffer.TYPE_BYTE));
|
assertThat(sampleModel.getDataType(), CoreMatchers.equalTo(DataBuffer.TYPE_BYTE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,7 +182,7 @@ public class DiscreteAlphaIndexColorModelTest {
|
|||||||
assertEquals(2, sampleModel.getHeight());
|
assertEquals(2, sampleModel.getHeight());
|
||||||
|
|
||||||
assertTrue(colorModel.isCompatibleSampleModel(sampleModel));
|
assertTrue(colorModel.isCompatibleSampleModel(sampleModel));
|
||||||
assertThat(sampleModel, CoreMatchers.is(PixelInterleavedSampleModel.class));
|
assertThat(sampleModel, instanceOf(PixelInterleavedSampleModel.class));
|
||||||
assertThat(sampleModel.getDataType(), CoreMatchers.equalTo(DataBuffer.TYPE_USHORT));
|
assertThat(sampleModel.getDataType(), CoreMatchers.equalTo(DataBuffer.TYPE_USHORT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ import static org.junit.Assert.*;
|
|||||||
*/
|
*/
|
||||||
public class ProviderInfoTest {
|
public class ProviderInfoTest {
|
||||||
@Test
|
@Test
|
||||||
public void testCreateNorma() {
|
public void testCreateNormal() {
|
||||||
new ProviderInfo(Package.getPackage("java.util"));
|
new ProviderInfo(Package.getPackage("java.util"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,8 +31,8 @@
|
|||||||
package com.twelvemonkeys.imageio.spi;
|
package com.twelvemonkeys.imageio.spi;
|
||||||
|
|
||||||
import org.hamcrest.Description;
|
import org.hamcrest.Description;
|
||||||
|
import org.hamcrest.TypeSafeMatcher;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.internal.matchers.TypeSafeMatcher;
|
|
||||||
|
|
||||||
import javax.imageio.ImageReader;
|
import javax.imageio.ImageReader;
|
||||||
import javax.imageio.ImageWriter;
|
import javax.imageio.ImageWriter;
|
||||||
@@ -42,6 +42,7 @@ import javax.imageio.spi.ImageWriterSpi;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static java.util.Arrays.asList;
|
import static java.util.Arrays.asList;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -62,52 +63,52 @@ public abstract class ReaderWriterProviderInfoTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void readerClassName() throws Exception {
|
public void readerClassName() {
|
||||||
assertClassExists(providerInfo.readerClassName(), ImageReader.class);
|
assertClassExists(providerInfo.readerClassName(), ImageReader.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void readerSpiClassNames() throws Exception {
|
public void readerSpiClassNames() {
|
||||||
assertClassesExist(providerInfo.readerSpiClassNames(), ImageReaderSpi.class);
|
assertClassesExist(providerInfo.readerSpiClassNames(), ImageReaderSpi.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void inputTypes() throws Exception {
|
public void inputTypes() {
|
||||||
assertNotNull(providerInfo.inputTypes());
|
assertNotNull(providerInfo.inputTypes());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void writerClassName() throws Exception {
|
public void writerClassName() {
|
||||||
assertClassExists(providerInfo.writerClassName(), ImageWriter.class);
|
assertClassExists(providerInfo.writerClassName(), ImageWriter.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void writerSpiClassNames() throws Exception {
|
public void writerSpiClassNames() {
|
||||||
assertClassesExist(providerInfo.writerSpiClassNames(), ImageWriterSpi.class);
|
assertClassesExist(providerInfo.writerSpiClassNames(), ImageWriterSpi.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void outputTypes() throws Exception {
|
public void outputTypes() {
|
||||||
assertNotNull(providerInfo.outputTypes());
|
assertNotNull(providerInfo.outputTypes());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void nativeStreamMetadataFormatClassName() throws Exception {
|
public void nativeStreamMetadataFormatClassName() {
|
||||||
assertClassExists(providerInfo.nativeStreamMetadataFormatClassName(), IIOMetadataFormat.class);
|
assertClassExists(providerInfo.nativeStreamMetadataFormatClassName(), IIOMetadataFormat.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void extraStreamMetadataFormatClassNames() throws Exception {
|
public void extraStreamMetadataFormatClassNames() {
|
||||||
assertClassesExist(providerInfo.extraStreamMetadataFormatClassNames(), IIOMetadataFormat.class);
|
assertClassesExist(providerInfo.extraStreamMetadataFormatClassNames(), IIOMetadataFormat.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void nativeImageMetadataFormatClassName() throws Exception {
|
public void nativeImageMetadataFormatClassName() {
|
||||||
assertClassExists(providerInfo.nativeImageMetadataFormatClassName(), IIOMetadataFormat.class);
|
assertClassExists(providerInfo.nativeImageMetadataFormatClassName(), IIOMetadataFormat.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void extraImageMetadataFormatClassNames() throws Exception {
|
public void extraImageMetadataFormatClassNames() {
|
||||||
assertClassesExist(providerInfo.extraImageMetadataFormatClassNames(), IIOMetadataFormat.class);
|
assertClassesExist(providerInfo.extraImageMetadataFormatClassNames(), IIOMetadataFormat.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +116,7 @@ public abstract class ReaderWriterProviderInfoTest {
|
|||||||
public void formatNames() {
|
public void formatNames() {
|
||||||
String[] names = providerInfo.formatNames();
|
String[] names = providerInfo.formatNames();
|
||||||
assertNotNull(names);
|
assertNotNull(names);
|
||||||
assertFalse(names.length == 0);
|
assertNotEquals(0, names.length);
|
||||||
|
|
||||||
List<String> list = asList(names);
|
List<String> list = asList(names);
|
||||||
|
|
||||||
@@ -132,7 +133,7 @@ public abstract class ReaderWriterProviderInfoTest {
|
|||||||
public void suffixes() {
|
public void suffixes() {
|
||||||
String[] suffixes = providerInfo.suffixes();
|
String[] suffixes = providerInfo.suffixes();
|
||||||
assertNotNull(suffixes);
|
assertNotNull(suffixes);
|
||||||
assertFalse(suffixes.length == 0);
|
assertNotEquals(0, suffixes.length);
|
||||||
|
|
||||||
for (String suffix : suffixes) {
|
for (String suffix : suffixes) {
|
||||||
assertNotNull(suffix);
|
assertNotNull(suffix);
|
||||||
@@ -144,7 +145,7 @@ public abstract class ReaderWriterProviderInfoTest {
|
|||||||
public void mimeTypes() {
|
public void mimeTypes() {
|
||||||
String[] mimeTypes = providerInfo.mimeTypes();
|
String[] mimeTypes = providerInfo.mimeTypes();
|
||||||
assertNotNull(mimeTypes);
|
assertNotNull(mimeTypes);
|
||||||
assertFalse(mimeTypes.length == 0);
|
assertNotEquals(0, mimeTypes.length);
|
||||||
|
|
||||||
for (String mimeType : mimeTypes) {
|
for (String mimeType : mimeTypes) {
|
||||||
assertNotNull(mimeType);
|
assertNotNull(mimeType);
|
||||||
|
|||||||
@@ -32,16 +32,19 @@ package com.twelvemonkeys.imageio.stream;
|
|||||||
|
|
||||||
import com.twelvemonkeys.io.ole2.CompoundDocument;
|
import com.twelvemonkeys.io.ole2.CompoundDocument;
|
||||||
import com.twelvemonkeys.io.ole2.Entry;
|
import com.twelvemonkeys.io.ole2.Entry;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import javax.imageio.stream.MemoryCacheImageInputStream;
|
import javax.imageio.stream.MemoryCacheImageInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import static java.util.Arrays.fill;
|
import static java.util.Arrays.fill;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BufferedImageInputStreamTest
|
* BufferedImageInputStreamTest
|
||||||
@@ -72,6 +75,257 @@ public class BufferedImageInputStreamTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadBit() throws IOException {
|
||||||
|
byte[] bytes = new byte[] {(byte) 0xF0, (byte) 0x0F};
|
||||||
|
|
||||||
|
// Create wrapper stream
|
||||||
|
BufferedImageInputStream stream = new BufferedImageInputStream(new ByteArrayImageInputStream(bytes));
|
||||||
|
|
||||||
|
// Read all bits
|
||||||
|
assertEquals(1, stream.readBit());
|
||||||
|
assertEquals(1, stream.getBitOffset());
|
||||||
|
assertEquals(0, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(1, stream.readBit());
|
||||||
|
assertEquals(2, stream.getBitOffset());
|
||||||
|
assertEquals(0, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(1, stream.readBit());
|
||||||
|
assertEquals(3, stream.getBitOffset());
|
||||||
|
assertEquals(0, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(1, stream.readBit());
|
||||||
|
assertEquals(4, stream.getBitOffset());
|
||||||
|
assertEquals(0, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(0, stream.readBit());
|
||||||
|
assertEquals(5, stream.getBitOffset());
|
||||||
|
assertEquals(0, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(0, stream.readBit());
|
||||||
|
assertEquals(6, stream.getBitOffset());
|
||||||
|
assertEquals(0, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(0, stream.readBit());
|
||||||
|
assertEquals(7, stream.getBitOffset());
|
||||||
|
assertEquals(0, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(0, stream.readBit()); // last bit
|
||||||
|
assertEquals(0, stream.getBitOffset());
|
||||||
|
assertEquals(1, stream.getStreamPosition());
|
||||||
|
|
||||||
|
// Full reset, read same sequence again
|
||||||
|
stream.seek(0);
|
||||||
|
assertEquals(0, stream.getBitOffset());
|
||||||
|
assertEquals(0, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(1, stream.readBit());
|
||||||
|
assertEquals(1, stream.readBit());
|
||||||
|
assertEquals(1, stream.readBit());
|
||||||
|
assertEquals(1, stream.readBit());
|
||||||
|
assertEquals(0, stream.readBit());
|
||||||
|
assertEquals(0, stream.readBit());
|
||||||
|
assertEquals(0, stream.readBit());
|
||||||
|
assertEquals(0, stream.readBit());
|
||||||
|
|
||||||
|
assertEquals(0, stream.getBitOffset());
|
||||||
|
assertEquals(1, stream.getStreamPosition());
|
||||||
|
|
||||||
|
// Full reset, read partial
|
||||||
|
stream.seek(0);
|
||||||
|
|
||||||
|
assertEquals(1, stream.readBit());
|
||||||
|
assertEquals(1, stream.readBit());
|
||||||
|
|
||||||
|
// Byte reset, read same sequence again
|
||||||
|
stream.setBitOffset(0);
|
||||||
|
|
||||||
|
assertEquals(1, stream.readBit());
|
||||||
|
assertEquals(1, stream.readBit());
|
||||||
|
assertEquals(1, stream.readBit());
|
||||||
|
assertEquals(1, stream.readBit());
|
||||||
|
assertEquals(0, stream.readBit());
|
||||||
|
|
||||||
|
// Byte reset, read partial sequence again
|
||||||
|
stream.setBitOffset(3);
|
||||||
|
|
||||||
|
assertEquals(1, stream.readBit());
|
||||||
|
assertEquals(0, stream.readBit());
|
||||||
|
assertEquals(0, stream.getStreamPosition());
|
||||||
|
|
||||||
|
// Byte reset, read partial sequence again
|
||||||
|
stream.setBitOffset(6);
|
||||||
|
|
||||||
|
assertEquals(0, stream.readBit());
|
||||||
|
assertEquals(0, stream.readBit());
|
||||||
|
assertEquals(1, stream.getStreamPosition());
|
||||||
|
|
||||||
|
// Read all bits, second byte
|
||||||
|
assertEquals(0, stream.readBit());
|
||||||
|
assertEquals(1, stream.getBitOffset());
|
||||||
|
assertEquals(1, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(0, stream.readBit());
|
||||||
|
assertEquals(2, stream.getBitOffset());
|
||||||
|
assertEquals(1, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(0, stream.readBit());
|
||||||
|
assertEquals(3, stream.getBitOffset());
|
||||||
|
assertEquals(1, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(0, stream.readBit());
|
||||||
|
assertEquals(4, stream.getBitOffset());
|
||||||
|
assertEquals(1, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(1, stream.readBit());
|
||||||
|
assertEquals(5, stream.getBitOffset());
|
||||||
|
assertEquals(1, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(1, stream.readBit());
|
||||||
|
assertEquals(6, stream.getBitOffset());
|
||||||
|
assertEquals(1, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(1, stream.readBit());
|
||||||
|
assertEquals(7, stream.getBitOffset());
|
||||||
|
assertEquals(1, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(1, stream.readBit()); // last bit
|
||||||
|
assertEquals(0, stream.getBitOffset());
|
||||||
|
assertEquals(2, stream.getStreamPosition());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadBits() throws IOException {
|
||||||
|
byte[] bytes = new byte[] {(byte) 0xF0, (byte) 0xCC, (byte) 0xAA};
|
||||||
|
|
||||||
|
// Create wrapper stream
|
||||||
|
BufferedImageInputStream stream = new BufferedImageInputStream(new ByteArrayImageInputStream(bytes));
|
||||||
|
|
||||||
|
// Read all bits, first byte
|
||||||
|
assertEquals(3, stream.readBits(2));
|
||||||
|
assertEquals(2, stream.getBitOffset());
|
||||||
|
assertEquals(0, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(3, stream.readBits(2));
|
||||||
|
assertEquals(4, stream.getBitOffset());
|
||||||
|
assertEquals(0, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(0, stream.readBits(2));
|
||||||
|
assertEquals(6, stream.getBitOffset());
|
||||||
|
assertEquals(0, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(0, stream.readBits(2));
|
||||||
|
assertEquals(0, stream.getBitOffset());
|
||||||
|
assertEquals(1, stream.getStreamPosition());
|
||||||
|
|
||||||
|
// Read all bits, second byte
|
||||||
|
assertEquals(3, stream.readBits(2));
|
||||||
|
assertEquals(2, stream.getBitOffset());
|
||||||
|
assertEquals(1, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(0, stream.readBits(2));
|
||||||
|
assertEquals(4, stream.getBitOffset());
|
||||||
|
assertEquals(1, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(3, stream.readBits(2));
|
||||||
|
assertEquals(6, stream.getBitOffset());
|
||||||
|
assertEquals(1, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(0, stream.readBits(2));
|
||||||
|
assertEquals(0, stream.getBitOffset());
|
||||||
|
assertEquals(2, stream.getStreamPosition());
|
||||||
|
|
||||||
|
// Read all bits, third byte
|
||||||
|
assertEquals(2, stream.readBits(2));
|
||||||
|
assertEquals(2, stream.getBitOffset());
|
||||||
|
assertEquals(2, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(2, stream.readBits(2));
|
||||||
|
assertEquals(4, stream.getBitOffset());
|
||||||
|
assertEquals(2, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(2, stream.readBits(2));
|
||||||
|
assertEquals(6, stream.getBitOffset());
|
||||||
|
assertEquals(2, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(2, stream.readBits(2));
|
||||||
|
assertEquals(0, stream.getBitOffset());
|
||||||
|
assertEquals(3, stream.getStreamPosition());
|
||||||
|
|
||||||
|
// Full reset, read same sequence again
|
||||||
|
stream.seek(0);
|
||||||
|
assertEquals(0, stream.getBitOffset());
|
||||||
|
assertEquals(0, stream.getStreamPosition());
|
||||||
|
|
||||||
|
// Read all bits, increasing size
|
||||||
|
assertEquals(7, stream.readBits(3)); // 111
|
||||||
|
assertEquals(3, stream.getBitOffset());
|
||||||
|
assertEquals(0, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(8, stream.readBits(4)); // 1000
|
||||||
|
assertEquals(7, stream.getBitOffset());
|
||||||
|
assertEquals(0, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(12, stream.readBits(5)); // 01100
|
||||||
|
assertEquals(4, stream.getBitOffset());
|
||||||
|
assertEquals(1, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(50, stream.readBits(6)); // 110010
|
||||||
|
assertEquals(2, stream.getBitOffset());
|
||||||
|
assertEquals(2, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(42, stream.readBits(6)); // 101010
|
||||||
|
assertEquals(0, stream.getBitOffset());
|
||||||
|
assertEquals(3, stream.getStreamPosition());
|
||||||
|
|
||||||
|
// Full reset, read same sequence again
|
||||||
|
stream.seek(0);
|
||||||
|
assertEquals(0, stream.getBitOffset());
|
||||||
|
assertEquals(0, stream.getStreamPosition());
|
||||||
|
|
||||||
|
// Read all bits multi-byte
|
||||||
|
assertEquals(0xF0C, stream.readBits(12)); // 111100001100
|
||||||
|
assertEquals(4, stream.getBitOffset());
|
||||||
|
assertEquals(1, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(0xCAA, stream.readBits(12)); // 110010101010
|
||||||
|
assertEquals(0, stream.getBitOffset());
|
||||||
|
assertEquals(3, stream.getStreamPosition());
|
||||||
|
|
||||||
|
// Full reset, read same sequence again, all bits in one go
|
||||||
|
stream.seek(0);
|
||||||
|
assertEquals(0, stream.getBitOffset());
|
||||||
|
assertEquals(0, stream.getStreamPosition());
|
||||||
|
|
||||||
|
assertEquals(0xF0CCAA, stream.readBits(24));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadBitsRandom() throws IOException {
|
||||||
|
long value = random.nextLong();
|
||||||
|
byte[] bytes = new byte[8];
|
||||||
|
ByteBuffer.wrap(bytes).putLong(value);
|
||||||
|
|
||||||
|
// Create wrapper stream
|
||||||
|
BufferedImageInputStream stream = new BufferedImageInputStream(new ByteArrayImageInputStream(bytes));
|
||||||
|
|
||||||
|
for (int i = 1; i < 64; i++) {
|
||||||
|
stream.seek(0);
|
||||||
|
assertEquals(i + " bits differ", value >>> (64L - i), stream.readBits(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testClose() throws IOException {
|
||||||
|
// Create wrapper stream
|
||||||
|
ImageInputStream mock = mock(ImageInputStream.class);
|
||||||
|
BufferedImageInputStream stream = new BufferedImageInputStream(mock);
|
||||||
|
|
||||||
|
stream.close();
|
||||||
|
verify(mock, never()).close();
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Write other tests
|
// TODO: Write other tests
|
||||||
|
|
||||||
// TODO: Create test that exposes read += -1 (eof) bug
|
// TODO: Create test that exposes read += -1 (eof) bug
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.twelvemonkeys.imageio.stream;
|
||||||
|
|
||||||
|
import javax.imageio.spi.ImageInputStreamSpi;
|
||||||
|
|
||||||
|
public class ByteArrayImageInputStreamSpiTest extends ImageInputStreamSpiTest<byte[]> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ImageInputStreamSpi createProvider() {
|
||||||
|
return new ByteArrayImageInputStreamSpi();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected byte[] createInput() {
|
||||||
|
return new byte[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package com.twelvemonkeys.imageio.stream;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import javax.imageio.spi.ImageInputStreamSpi;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
abstract class ImageInputStreamSpiTest<T> {
|
||||||
|
private final ImageInputStreamSpi provider = createProvider();
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private final Class<T> inputClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
|
||||||
|
|
||||||
|
protected abstract ImageInputStreamSpi createProvider();
|
||||||
|
|
||||||
|
protected abstract T createInput();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInputClass() {
|
||||||
|
assertEquals(inputClass, provider.getInputClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVendorName() {
|
||||||
|
assertNotNull(provider.getVendorName());
|
||||||
|
assertEquals("TwelveMonkeys", provider.getVendorName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVersion() {
|
||||||
|
assertNotNull(provider.getVersion());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDescription() {
|
||||||
|
assertNotNull(provider.getDescription(null));
|
||||||
|
assertNotNull(provider.getDescription(Locale.ENGLISH));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void createNull() throws IOException {
|
||||||
|
provider.createInputStreamInstance(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException.class)
|
||||||
|
public void createNullCached() throws IOException {
|
||||||
|
provider.createInputStreamInstance(null, true, ImageIO.getCacheDirectory());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createCachedNullCache() throws IOException {
|
||||||
|
try {
|
||||||
|
provider.createInputStreamInstance(createInput(), true, null);
|
||||||
|
}
|
||||||
|
catch (IllegalArgumentException expected) {
|
||||||
|
// All good
|
||||||
|
assertFalse(provider.needsCacheFile());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void create() throws IOException {
|
||||||
|
assertNotNull(provider.createInputStreamInstance(createInput()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createCached() throws IOException {
|
||||||
|
if (provider.canUseCacheFile()) {
|
||||||
|
assertNotNull(provider.createInputStreamInstance(createInput(), true, ImageIO.getCacheDirectory()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createNonCached() throws IOException {
|
||||||
|
if (!provider.needsCacheFile()) {
|
||||||
|
assertNotNull(provider.createInputStreamInstance(createInput(), false, ImageIO.getCacheDirectory()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.twelvemonkeys.imageio.stream;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.imageio.spi.ProviderInfo;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
|
public class StreamProviderInfoTest {
|
||||||
|
private final ProviderInfo providerInfo = new StreamProviderInfo();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVendorName() {
|
||||||
|
assertNotNull(providerInfo.getVendorName());
|
||||||
|
assertEquals("TwelveMonkeys", providerInfo.getVendorName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVersion() {
|
||||||
|
assertNotNull(providerInfo.getVersion());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.twelvemonkeys.imageio.stream;
|
||||||
|
|
||||||
|
import javax.imageio.spi.ImageInputStreamSpi;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
public class URLImageInputStreamSpiTest extends ImageInputStreamSpiTest<URL> {
|
||||||
|
@Override
|
||||||
|
protected ImageInputStreamSpi createProvider() {
|
||||||
|
return new URLImageInputStreamSpi();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected URL createInput() {
|
||||||
|
return getClass().getResource("/empty-stream.txt");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,6 +31,7 @@
|
|||||||
package com.twelvemonkeys.imageio.util;
|
package com.twelvemonkeys.imageio.util;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.stream.URLImageInputStreamSpi;
|
import com.twelvemonkeys.imageio.stream.URLImageInputStreamSpi;
|
||||||
|
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.InOrder;
|
import org.mockito.InOrder;
|
||||||
@@ -49,6 +50,7 @@ import java.awt.image.RenderedImage;
|
|||||||
import java.awt.image.SampleModel;
|
import java.awt.image.SampleModel;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -69,27 +71,26 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
// TODO: Should we really test if the provider is installed?
|
// TODO: Should we really test if the provider is installed?
|
||||||
// - Pro: Tests the META-INF/services config
|
// - Pro: Tests the META-INF/services config
|
||||||
// - Con: Not all providers should be installed at runtime...
|
// - Con: Not all providers should be installed at runtime...
|
||||||
|
// TODO: Create own subclass for testing the Spis?
|
||||||
|
|
||||||
static {
|
static {
|
||||||
IIORegistry.getDefaultInstance().registerServiceProvider(new URLImageInputStreamSpi());
|
IIORegistry.getDefaultInstance().registerServiceProvider(new URLImageInputStreamSpi());
|
||||||
ImageIO.setUseCache(false);
|
ImageIO.setUseCache(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract List<TestData> getTestData();
|
@SuppressWarnings("unchecked")
|
||||||
|
private final Class<T> readerClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
|
||||||
|
|
||||||
|
protected final ImageReaderSpi provider = createProvider();
|
||||||
|
|
||||||
protected abstract ImageReaderSpi createProvider();
|
protected abstract ImageReaderSpi createProvider();
|
||||||
|
|
||||||
protected abstract Class<T> getReaderClass();
|
protected final T createReader() throws IOException {
|
||||||
|
return readerClass.cast(provider.createReaderInstance(null));
|
||||||
protected T createReader() {
|
|
||||||
try {
|
|
||||||
return getReaderClass().newInstance();
|
|
||||||
}
|
|
||||||
catch (InstantiationException | IllegalAccessException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract List<TestData> getTestData();
|
||||||
|
|
||||||
protected abstract List<String> getFormatNames();
|
protected abstract List<String> getFormatNames();
|
||||||
|
|
||||||
protected abstract List<String> getSuffixes();
|
protected abstract List<String> getSuffixes();
|
||||||
@@ -101,9 +102,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected static void failBecause(String message, Throwable exception) {
|
protected static void failBecause(String message, Throwable exception) {
|
||||||
AssertionError error = new AssertionError(message);
|
throw new AssertionError(message, exception);
|
||||||
error.initCause(exception);
|
|
||||||
throw error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void assertProviderInstalledForName(final String pFormat, final Class<? extends ImageReader> pReaderClass) {
|
protected void assertProviderInstalledForName(final String pFormat, final Class<? extends ImageReader> pReaderClass) {
|
||||||
@@ -123,17 +122,20 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
boolean found = false;
|
boolean found = false;
|
||||||
while (pReaders.hasNext()) {
|
while (pReaders.hasNext()) {
|
||||||
ImageReader reader = pReaders.next();
|
ImageReader reader = pReaders.next();
|
||||||
if (reader.getClass() == pReaderClass) {
|
if (reader.getClass() == pReaderClass && isOurProvider(reader.getOriginatingProvider())) {
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTrue(String.format("%s not installed for %s", pReaderClass.getSimpleName(), pFormat), found);
|
assertTrue(String.format("%s not provided by %s for '%s'", pReaderClass.getSimpleName(), provider.getClass().getSimpleName(), pFormat), found);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isOurProvider(final ImageReaderSpi spi) {
|
||||||
|
return provider.getClass().isInstance(spi);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProviderInstalledForNames() {
|
public void testProviderInstalledForNames() {
|
||||||
Class<? extends ImageReader> readerClass = getReaderClass();
|
|
||||||
for (String name : getFormatNames()) {
|
for (String name : getFormatNames()) {
|
||||||
assertProviderInstalledForName(name, readerClass);
|
assertProviderInstalledForName(name, readerClass);
|
||||||
}
|
}
|
||||||
@@ -141,7 +143,6 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProviderInstalledForSuffixes() {
|
public void testProviderInstalledForSuffixes() {
|
||||||
Class<? extends ImageReader> readerClass = getReaderClass();
|
|
||||||
for (String suffix : getSuffixes()) {
|
for (String suffix : getSuffixes()) {
|
||||||
assertProviderInstalledForSuffix(suffix, readerClass);
|
assertProviderInstalledForSuffix(suffix, readerClass);
|
||||||
}
|
}
|
||||||
@@ -149,7 +150,6 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProviderInstalledForMIMETypes() {
|
public void testProviderInstalledForMIMETypes() {
|
||||||
Class<? extends ImageReader> readerClass = getReaderClass();
|
|
||||||
for (String type : getMIMETypes()) {
|
for (String type : getMIMETypes()) {
|
||||||
assertProviderInstalledForMIMEType(type, readerClass);
|
assertProviderInstalledForMIMEType(type, readerClass);
|
||||||
}
|
}
|
||||||
@@ -159,7 +159,6 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
public void testProviderCanRead() throws IOException {
|
public void testProviderCanRead() throws IOException {
|
||||||
List<TestData> testData = getTestData();
|
List<TestData> testData = getTestData();
|
||||||
|
|
||||||
ImageReaderSpi provider = createProvider();
|
|
||||||
for (TestData data : testData) {
|
for (TestData data : testData) {
|
||||||
ImageInputStream stream = data.getInputStream();
|
ImageInputStream stream = data.getInputStream();
|
||||||
assertNotNull(stream);
|
assertNotNull(stream);
|
||||||
@@ -172,7 +171,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
boolean canRead = false;
|
boolean canRead = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
canRead = createProvider().canDecodeInput(null);
|
canRead = provider.canDecodeInput(null);
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException ignore) {
|
catch (IllegalArgumentException ignore) {
|
||||||
}
|
}
|
||||||
@@ -187,7 +186,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetInput() {
|
public void testSetInput() throws IOException {
|
||||||
// Should just pass with no exceptions
|
// Should just pass with no exceptions
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
assertNotNull(reader);
|
assertNotNull(reader);
|
||||||
@@ -200,7 +199,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetInputNull() {
|
public void testSetInputNull() throws IOException {
|
||||||
// Should just pass with no exceptions
|
// Should just pass with no exceptions
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
assertNotNull(reader);
|
assertNotNull(reader);
|
||||||
@@ -209,7 +208,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRead() {
|
public void testRead() throws IOException {
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
|
|
||||||
for (TestData data : getTestData()) {
|
for (TestData data : getTestData()) {
|
||||||
@@ -243,7 +242,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadIndexNegative() {
|
public void testReadIndexNegative() 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());
|
||||||
@@ -264,7 +263,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadIndexOutOfBounds() {
|
public void testReadIndexOutOfBounds() 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());
|
||||||
@@ -285,7 +284,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadNoInput() {
|
public void testReadNoInput() throws IOException {
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
// Do not set input
|
// Do not set input
|
||||||
|
|
||||||
@@ -325,7 +324,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadIndexNegativeWithParam() {
|
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());
|
||||||
@@ -347,7 +346,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadIndexOutOfBoundsWithParam() {
|
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());
|
||||||
@@ -369,7 +368,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadNoInputWithParam() {
|
public void testReadNoInputWithParam() throws IOException {
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
// Do not set input
|
// Do not set input
|
||||||
|
|
||||||
@@ -390,7 +389,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadWithNewParam() {
|
public void testReadWithNewParam() 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());
|
||||||
@@ -411,7 +410,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadWithDefaultParam() {
|
public void testReadWithDefaultParam() 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());
|
||||||
@@ -432,7 +431,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadWithNullParam() {
|
public void testReadWithNullParam() 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());
|
||||||
@@ -453,7 +452,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadWithSizeParam() {
|
public void testReadWithSizeParam() 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());
|
||||||
@@ -479,7 +478,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadWithSubsampleParamDimensions() {
|
public void testReadWithSubsampleParamDimensions() 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());
|
||||||
@@ -530,6 +529,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
// TODO: Subsample all test data
|
// TODO: Subsample all test data
|
||||||
// TODO: Subsample with varying ratios and offsets
|
// TODO: Subsample with varying ratios and offsets
|
||||||
|
|
||||||
|
@SuppressWarnings("SameParameterValue")
|
||||||
protected final void assertSubsampledImageDataEquals(String message, BufferedImage expected, BufferedImage actual, ImageReadParam param) throws IOException {
|
protected final void assertSubsampledImageDataEquals(String message, BufferedImage expected, BufferedImage actual, ImageReadParam param) throws IOException {
|
||||||
assertNotNull("Expected image was null", expected);
|
assertNotNull("Expected image was null", expected);
|
||||||
assertNotNull("Actual image was null!", actual);
|
assertNotNull("Actual image was null!", actual);
|
||||||
@@ -553,10 +553,10 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
int actualRGB = actual.getRGB(x, y);
|
int actualRGB = actual.getRGB(x, y);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
assertEquals(String.format("%s alpha at (%d, %d)", message, x, y), (expectedRGB >>> 24) & 0xff, (actualRGB >>> 24) & 0xff, 5);
|
assertEquals((expectedRGB >>> 24) & 0xff, (actualRGB >>> 24) & 0xff, 5);
|
||||||
assertEquals(String.format("%s red at (%d, %d)", message, x, y), (expectedRGB >> 16) & 0xff, (actualRGB >> 16) & 0xff, 5);
|
assertEquals((expectedRGB >> 16) & 0xff, (actualRGB >> 16) & 0xff, 5);
|
||||||
assertEquals(String.format("%s green at (%d, %d)", message, x, y), (expectedRGB >> 8) & 0xff, (actualRGB >> 8) & 0xff, 5);
|
assertEquals((expectedRGB >> 8) & 0xff, (actualRGB >> 8) & 0xff, 5);
|
||||||
assertEquals(String.format("%s blue at (%d, %d)", message, x, y), expectedRGB & 0xff, actualRGB & 0xff, 5);
|
assertEquals(expectedRGB & 0xff, actualRGB & 0xff, 5);
|
||||||
}
|
}
|
||||||
catch (AssertionError e) {
|
catch (AssertionError e) {
|
||||||
File tempExpected = File.createTempFile("junit-expected-", ".png");
|
File tempExpected = File.createTempFile("junit-expected-", ".png");
|
||||||
@@ -566,7 +566,6 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
System.err.println("tempActual.getAbsolutePath(): " + tempActual.getAbsolutePath());
|
System.err.println("tempActual.getAbsolutePath(): " + tempActual.getAbsolutePath());
|
||||||
ImageIO.write(actual, "PNG", tempActual);
|
ImageIO.write(actual, "PNG", tempActual);
|
||||||
|
|
||||||
|
|
||||||
assertEquals(String.format("%s ARGB at (%d, %d)", message, x, y), String.format("#%08x", expectedRGB), String.format("#%08x", actualRGB));
|
assertEquals(String.format("%s ARGB at (%d, %d)", message, x, y), String.format("#%08x", expectedRGB), String.format("#%08x", actualRGB));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -595,7 +594,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadWithSourceRegionParam() {
|
public void testReadWithSourceRegionParam() 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());
|
||||||
@@ -626,40 +625,53 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
|
|
||||||
protected void assertReadWithSourceRegionParamEqualImage(final Rectangle r, final TestData data, final int imageIndex) throws IOException {
|
protected void assertReadWithSourceRegionParamEqualImage(final Rectangle r, final TestData data, final int imageIndex) throws IOException {
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
reader.setInput(data.getInputStream());
|
try (ImageInputStream inputStream = data.getInputStream()) {
|
||||||
ImageReadParam param = reader.getDefaultReadParam();
|
reader.setInput(inputStream);
|
||||||
|
ImageReadParam param = reader.getDefaultReadParam();
|
||||||
|
|
||||||
// Read full image and get sub image for comparison
|
// Read full image and get sub image for comparison
|
||||||
final BufferedImage roi = reader.read(imageIndex, param).getSubimage(r.x, r.y, r.width, r.height);
|
BufferedImage original = reader.read(imageIndex, param);
|
||||||
|
final BufferedImage roi = original.getSubimage(r.x, r.y, r.width, r.height);
|
||||||
|
|
||||||
param.setSourceRegion(r);
|
param.setSourceRegion(r);
|
||||||
|
|
||||||
final BufferedImage image = reader.read(imageIndex, param);
|
final BufferedImage image = reader.read(imageIndex, param);
|
||||||
|
|
||||||
// try {
|
assertNotNull("Image was null!", image);
|
||||||
// SwingUtilities.invokeAndWait(new Runnable() {
|
assertEquals("Read image has wrong width: " + image.getWidth(), r.width, image.getWidth());
|
||||||
// public void run() {
|
assertEquals("Read image has wrong height: " + image.getHeight(), r.height, image.getHeight());
|
||||||
// JPanel panel = new JPanel(new FlowLayout());
|
|
||||||
// panel.add(new JLabel(new BufferedImageIcon(roi, r.width * 10, r.height * 10, true)));
|
|
||||||
// panel.add(new JLabel(new BufferedImageIcon(image, r.width * 10, r.height * 10, true)));
|
|
||||||
// JOptionPane.showConfirmDialog(null, panel);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// catch (Exception e) {
|
|
||||||
// throw new RuntimeException(e);
|
|
||||||
// }
|
|
||||||
|
|
||||||
assertNotNull("Image was null!", image);
|
try {
|
||||||
assertEquals("Read image has wrong width: " + image.getWidth(), r.width, image.getWidth());
|
assertImageDataEquals("Images differ", roi, image);
|
||||||
assertEquals("Read image has wrong height: " + image.getHeight(), r.height, image.getHeight());
|
}
|
||||||
assertImageDataEquals("Images differ", roi, image);
|
catch (AssertionError e) {
|
||||||
|
File tempExpected = File.createTempFile("junit-expected-", ".png");
|
||||||
|
System.err.println("tempExpected.getAbsolutePath(): " + tempExpected.getAbsolutePath());
|
||||||
|
|
||||||
reader.dispose();
|
Graphics2D graphics = original.createGraphics();
|
||||||
|
try {
|
||||||
|
graphics.setColor(Color.RED);
|
||||||
|
graphics.draw(r);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
graphics.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageIO.write(original, "PNG", tempExpected);
|
||||||
|
File tempActual = File.createTempFile("junit-actual-", ".png");
|
||||||
|
System.err.println("tempActual.getAbsolutePath(): " + tempActual.getAbsolutePath());
|
||||||
|
ImageIO.write(image, "PNG", tempActual);
|
||||||
|
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
reader.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadWithSizeAndSourceRegionParam() {
|
public void testReadWithSizeAndSourceRegionParam() throws IOException {
|
||||||
// TODO: Is this test correct???
|
// TODO: Is this test correct???
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
TestData data = getTestData().get(0);
|
TestData data = getTestData().get(0);
|
||||||
@@ -690,7 +702,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadWithSubsampleAndSourceRegionParam() {
|
public void testReadWithSubsampleAndSourceRegionParam() throws IOException {
|
||||||
// NOTE: The "standard" (com.sun.imageio.plugin.*) ImageReaders pass
|
// NOTE: The "standard" (com.sun.imageio.plugin.*) ImageReaders pass
|
||||||
// this test, so the test should be correct...
|
// this test, so the test should be correct...
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
@@ -716,7 +728,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadAsRenderedImageIndexNegative() {
|
public void testReadAsRenderedImageIndexNegative() 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());
|
||||||
@@ -739,7 +751,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadAsRenderedImageIndexOutOfBounds() throws IIOException {
|
public void testReadAsRenderedImageIndexOutOfBounds() 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());
|
||||||
@@ -766,7 +778,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadAsRenderedImageNoInput() {
|
public void testReadAsRenderedImageNoInput() throws IOException {
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
// Do not set input
|
// Do not set input
|
||||||
|
|
||||||
@@ -788,7 +800,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadAsRenderedImage() {
|
public void testReadAsRenderedImage() 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());
|
||||||
@@ -811,7 +823,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadAsRenderedImageWithDefaultParam() {
|
public void testReadAsRenderedImageWithDefaultParam() 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());
|
||||||
@@ -834,7 +846,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetDefaultReadParam() {
|
public void testGetDefaultReadParam() throws IOException {
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
ImageReadParam param = reader.getDefaultReadParam();
|
ImageReadParam param = reader.getDefaultReadParam();
|
||||||
assertNotNull(param);
|
assertNotNull(param);
|
||||||
@@ -842,7 +854,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetFormatName() {
|
public void testGetFormatName() 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());
|
||||||
@@ -858,7 +870,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetMinIndex() {
|
public void testGetMinIndex() 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());
|
||||||
@@ -874,7 +886,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetMinIndexNoInput() {
|
public void testGetMinIndexNoInput() throws IOException {
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
int num = 0;
|
int num = 0;
|
||||||
|
|
||||||
@@ -888,7 +900,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetNumImages() {
|
public void testGetNumImages() 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());
|
||||||
@@ -917,7 +929,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetNumImagesNoInput() {
|
public void testGetNumImagesNoInput() throws IOException {
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
int num = -1;
|
int num = -1;
|
||||||
|
|
||||||
@@ -945,7 +957,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetWidth() {
|
public void testGetWidth() 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());
|
||||||
@@ -962,7 +974,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetWidthIndexOutOfBounds() {
|
public void testGetWidthIndexOutOfBounds() 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());
|
||||||
@@ -983,13 +995,13 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetWidthNoInput() {
|
public void testGetWidthNoInput() throws IOException {
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
|
|
||||||
int width = 0;
|
int width = 0;
|
||||||
try {
|
try {
|
||||||
width = reader.getWidth(0);
|
width = reader.getWidth(0);
|
||||||
fail("Width read without imput");
|
fail("Width read without input");
|
||||||
}
|
}
|
||||||
catch (IllegalStateException ignore) {
|
catch (IllegalStateException ignore) {
|
||||||
}
|
}
|
||||||
@@ -1001,7 +1013,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetHeight() {
|
public void testGetHeight() 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());
|
||||||
@@ -1018,13 +1030,13 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetHeightNoInput() {
|
public void testGetHeightNoInput() throws IOException {
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
|
|
||||||
int height = 0;
|
int height = 0;
|
||||||
try {
|
try {
|
||||||
height = reader.getHeight(0);
|
height = reader.getHeight(0);
|
||||||
fail("height read without imput");
|
fail("height read without input");
|
||||||
}
|
}
|
||||||
catch (IllegalStateException ignore) {
|
catch (IllegalStateException ignore) {
|
||||||
}
|
}
|
||||||
@@ -1036,7 +1048,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetHeightIndexOutOfBounds() {
|
public void testGetHeightIndexOutOfBounds() 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());
|
||||||
@@ -1057,7 +1069,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetAspectRatio() {
|
public void testGetAspectRatio() 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());
|
||||||
@@ -1075,7 +1087,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetAspectRatioNoInput() {
|
public void testGetAspectRatioNoInput() throws IOException {
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
|
|
||||||
float aspectRatio = 0f;
|
float aspectRatio = 0f;
|
||||||
@@ -1093,7 +1105,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetAspectRatioIndexOutOfBounds() {
|
public void testGetAspectRatioIndexOutOfBounds() 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());
|
||||||
@@ -1114,13 +1126,13 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDisposeBeforeRead() {
|
public void testDisposeBeforeRead() throws IOException {
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
reader.dispose(); // Just pass with no exceptions
|
reader.dispose(); // Just pass with no exceptions
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDisposeAfterRead() {
|
public void testDisposeAfterRead() 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());
|
||||||
@@ -1128,21 +1140,21 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddIIOReadProgressListener() {
|
public void testAddIIOReadProgressListener() throws IOException {
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
reader.addIIOReadProgressListener(mock(IIOReadProgressListener.class));
|
reader.addIIOReadProgressListener(mock(IIOReadProgressListener.class));
|
||||||
reader.dispose();
|
reader.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddIIOReadProgressListenerNull() {
|
public void testAddIIOReadProgressListenerNull() throws IOException {
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
reader.addIIOReadProgressListener(null);
|
reader.addIIOReadProgressListener(null);
|
||||||
reader.dispose();
|
reader.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddIIOReadProgressListenerCallbacks() {
|
public void testAddIIOReadProgressListenerCallbacks() 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());
|
||||||
@@ -1166,7 +1178,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMultipleAddIIOReadProgressListenerCallbacks() {
|
public void testMultipleAddIIOReadProgressListenerCallbacks() 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());
|
||||||
@@ -1204,21 +1216,21 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRemoveIIOReadProgressListenerNull() {
|
public void testRemoveIIOReadProgressListenerNull() throws IOException {
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
reader.removeIIOReadProgressListener(null);
|
reader.removeIIOReadProgressListener(null);
|
||||||
reader.dispose();
|
reader.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRemoveIIOReadProgressListenerNone() {
|
public void testRemoveIIOReadProgressListenerNone() throws IOException {
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
reader.removeIIOReadProgressListener(mock(IIOReadProgressListener.class));
|
reader.removeIIOReadProgressListener(mock(IIOReadProgressListener.class));
|
||||||
reader.dispose();
|
reader.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRemoveIIOReadProgressListener() {
|
public void testRemoveIIOReadProgressListener() 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());
|
||||||
@@ -1240,7 +1252,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRemoveIIOReadProgressListenerMultiple() {
|
public void testRemoveIIOReadProgressListenerMultiple() 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());
|
||||||
@@ -1272,7 +1284,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRemoveAllIIOReadProgressListeners() {
|
public void testRemoveAllIIOReadProgressListeners() 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());
|
||||||
@@ -1295,7 +1307,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRemoveAllIIOReadProgressListenersMultiple() {
|
public void testRemoveAllIIOReadProgressListenersMultiple() 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());
|
||||||
@@ -1322,7 +1334,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAbort() {
|
public void testAbort() throws IOException {
|
||||||
final ImageReader reader = createReader();
|
final ImageReader reader = createReader();
|
||||||
TestData data = getTestData().get(0);
|
TestData data = getTestData().get(0);
|
||||||
reader.setInput(data.getInputStream());
|
reader.setInput(data.getInputStream());
|
||||||
@@ -1336,7 +1348,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
// Create a listener that just makes the reader abort immediately...
|
// Create a listener that just makes the reader abort immediately...
|
||||||
IIOReadProgressListener abortingListener = mock(IIOReadProgressListener.class, "Aborter");
|
IIOReadProgressListener abortingListener = mock(IIOReadProgressListener.class, "Aborter");
|
||||||
Answer<Void> abort = new Answer<Void>() {
|
Answer<Void> abort = new Answer<Void>() {
|
||||||
public Void answer(InvocationOnMock invocation) throws Throwable {
|
public Void answer(InvocationOnMock invocation) {
|
||||||
reader.abort();
|
reader.abort();
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -1387,7 +1399,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTrue("ImageTypeSepcifier 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();
|
||||||
}
|
}
|
||||||
@@ -1569,7 +1581,6 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
reader.dispose();
|
reader.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetDestinationOffsetNull() throws IOException {
|
public void testSetDestinationOffsetNull() throws IOException {
|
||||||
final ImageReader reader = createReader();
|
final ImageReader reader = createReader();
|
||||||
@@ -1620,7 +1631,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
assertEquals(expectedModel.getDataType(), resultModel.getDataType());
|
assertEquals(expectedModel.getDataType(), resultModel.getDataType());
|
||||||
assertEquals(expectedModel.getNumBands(), resultModel.getNumBands());
|
assertEquals(expectedModel.getNumBands(), resultModel.getNumBands());
|
||||||
assertEquals(expectedModel.getNumDataElements(), resultModel.getNumDataElements());
|
assertEquals(expectedModel.getNumDataElements(), resultModel.getNumDataElements());
|
||||||
assertTrue(Arrays.equals(expectedModel.getSampleSize(), resultModel.getSampleSize()));
|
assertArrayEquals(expectedModel.getSampleSize(), resultModel.getSampleSize());
|
||||||
assertEquals(expectedModel.getTransferType(), resultModel.getTransferType());
|
assertEquals(expectedModel.getTransferType(), resultModel.getTransferType());
|
||||||
for (int i = 0; i < expectedModel.getNumBands(); i++) {
|
for (int i = 0; i < expectedModel.getNumBands(); i++) {
|
||||||
assertEquals(expectedModel.getSampleSize(i), resultModel.getSampleSize(i));
|
assertEquals(expectedModel.getSampleSize(i), resultModel.getSampleSize(i));
|
||||||
@@ -1692,20 +1703,18 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
|
|
||||||
@Ignore("TODO: Implement")
|
@Ignore("TODO: Implement")
|
||||||
@Test
|
@Test
|
||||||
public void testSetDestinationBands() throws IOException {
|
public void testSetDestinationBands() {
|
||||||
throw new UnsupportedOperationException("Method testSetDestinationBands not implemented"); // TODO: Implement
|
throw new UnsupportedOperationException("Method testSetDestinationBands not implemented"); // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("TODO: Implement")
|
@Ignore("TODO: Implement")
|
||||||
@Test
|
@Test
|
||||||
public void testSetSourceBands() throws IOException {
|
public void testSetSourceBands() {
|
||||||
throw new UnsupportedOperationException("Method testSetDestinationBands not implemented"); // TODO: Implement
|
throw new UnsupportedOperationException("Method testSetDestinationBands not implemented"); // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProviderAndMetadataFormatNamesMatch() throws IOException {
|
public void testProviderAndMetadataFormatNamesMatch() throws IOException {
|
||||||
ImageReaderSpi provider = createProvider();
|
|
||||||
|
|
||||||
ImageReader reader = createReader();
|
ImageReader reader = createReader();
|
||||||
reader.setInput(getTestData().get(0).getInputStream());
|
reader.setInput(getTestData().get(0).getInputStream());
|
||||||
|
|
||||||
@@ -1826,7 +1835,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return getClass().getSimpleName() + ": " + String.valueOf(input);
|
return String.format("%s: %s", getClass().getSimpleName(), input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
package com.twelvemonkeys.imageio.util;
|
package com.twelvemonkeys.imageio.util;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.stream.URLImageInputStreamSpi;
|
import com.twelvemonkeys.imageio.stream.URLImageInputStreamSpi;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.InOrder;
|
import org.mockito.InOrder;
|
||||||
|
|
||||||
@@ -39,12 +40,14 @@ import javax.imageio.ImageWriteParam;
|
|||||||
import javax.imageio.ImageWriter;
|
import javax.imageio.ImageWriter;
|
||||||
import javax.imageio.event.IIOWriteProgressListener;
|
import javax.imageio.event.IIOWriteProgressListener;
|
||||||
import javax.imageio.spi.IIORegistry;
|
import javax.imageio.spi.IIORegistry;
|
||||||
|
import javax.imageio.spi.ImageWriterSpi;
|
||||||
import javax.imageio.stream.ImageOutputStream;
|
import javax.imageio.stream.ImageOutputStream;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.RenderedImage;
|
import java.awt.image.RenderedImage;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -59,7 +62,7 @@ import static org.mockito.Mockito.*;
|
|||||||
* @author last modified by $Author: haku $
|
* @author last modified by $Author: haku $
|
||||||
* @version $Id: ImageReaderAbstractTestCase.java,v 1.0 18.nov.2004 17:38:33 haku Exp $
|
* @version $Id: ImageReaderAbstractTestCase.java,v 1.0 18.nov.2004 17:38:33 haku Exp $
|
||||||
*/
|
*/
|
||||||
public abstract class ImageWriterAbstractTest {
|
public abstract class ImageWriterAbstractTest<T extends ImageWriter> {
|
||||||
|
|
||||||
// TODO: Move static block + getClassLoaderResource to common superclass for reader/writer test cases or delegate.
|
// TODO: Move static block + getClassLoaderResource to common superclass for reader/writer test cases or delegate.
|
||||||
|
|
||||||
@@ -68,7 +71,16 @@ public abstract class ImageWriterAbstractTest {
|
|||||||
ImageIO.setUseCache(false);
|
ImageIO.setUseCache(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract ImageWriter createImageWriter();
|
@SuppressWarnings("unchecked")
|
||||||
|
private final Class<T> writerClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
|
||||||
|
|
||||||
|
protected final ImageWriterSpi provider = createProvider();
|
||||||
|
|
||||||
|
protected abstract ImageWriterSpi createProvider();
|
||||||
|
|
||||||
|
protected final T createWriter() throws IOException {
|
||||||
|
return writerClass.cast(provider.createWriterInstance(null));
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract List<? extends RenderedImage> getTestData();
|
protected abstract List<? extends RenderedImage> getTestData();
|
||||||
|
|
||||||
@@ -104,22 +116,22 @@ public abstract class ImageWriterAbstractTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testSetOutput() throws IOException {
|
public void testSetOutput() throws IOException {
|
||||||
// Should just pass with no exceptions
|
// Should just pass with no exceptions
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
assertNotNull(writer);
|
assertNotNull(writer);
|
||||||
writer.setOutput(ImageIO.createImageOutputStream(new ByteArrayOutputStream()));
|
writer.setOutput(ImageIO.createImageOutputStream(new ByteArrayOutputStream()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSetOutputNull() {
|
public void testSetOutputNull() throws IOException {
|
||||||
// Should just pass with no exceptions
|
// Should just pass with no exceptions
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
assertNotNull(writer);
|
assertNotNull(writer);
|
||||||
writer.setOutput(null);
|
writer.setOutput(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWrite() throws IOException {
|
public void testWrite() throws IOException {
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
|
|
||||||
for (RenderedImage testData : getTestData()) {
|
for (RenderedImage testData : getTestData()) {
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
@@ -129,17 +141,16 @@ public abstract class ImageWriterAbstractTest {
|
|||||||
writer.write(drawSomething((BufferedImage) testData));
|
writer.write(drawSomething((BufferedImage) testData));
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
fail(e.getMessage());
|
throw new AssertionError(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTrue("No image data written", buffer.size() > 0);
|
assertTrue("No image data written", buffer.size() > 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
|
||||||
@Test
|
@Test
|
||||||
public void testWriteNull() throws IOException {
|
public void testWriteNull() throws IOException {
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
writer.setOutput(ImageIO.createImageOutputStream(buffer));
|
writer.setOutput(ImageIO.createImageOutputStream(buffer));
|
||||||
|
|
||||||
@@ -149,15 +160,15 @@ public abstract class ImageWriterAbstractTest {
|
|||||||
catch(IllegalArgumentException ignore) {
|
catch(IllegalArgumentException ignore) {
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
fail(e.getMessage());
|
throw new AssertionError(e.getMessage(), e);
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTrue("Image data written", buffer.size() == 0);
|
assertEquals("Image data written", 0, buffer.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalStateException.class)
|
@Test(expected = IllegalStateException.class)
|
||||||
public void testWriteNoOutput() {
|
public void testWriteNoOutput() throws IOException {
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
writer.write(getTestData(0));
|
writer.write(getTestData(0));
|
||||||
@@ -168,8 +179,8 @@ public abstract class ImageWriterAbstractTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetDefaultWriteParam() {
|
public void testGetDefaultWriteParam() throws IOException {
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
ImageWriteParam param = writer.getDefaultWriteParam();
|
ImageWriteParam param = writer.getDefaultWriteParam();
|
||||||
assertNotNull("Default ImageWriteParam is null", param);
|
assertNotNull("Default ImageWriteParam is null", param);
|
||||||
}
|
}
|
||||||
@@ -178,20 +189,20 @@ public abstract class ImageWriterAbstractTest {
|
|||||||
// TODO: Source region and subsampling at least
|
// TODO: Source region and subsampling at least
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddIIOWriteProgressListener() {
|
public void testAddIIOWriteProgressListener() throws IOException {
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
writer.addIIOWriteProgressListener(mock(IIOWriteProgressListener.class));
|
writer.addIIOWriteProgressListener(mock(IIOWriteProgressListener.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddIIOWriteProgressListenerNull() {
|
public void testAddIIOWriteProgressListenerNull() throws IOException {
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
writer.addIIOWriteProgressListener(null);
|
writer.addIIOWriteProgressListener(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddIIOWriteProgressListenerCallbacks() throws IOException {
|
public void testAddIIOWriteProgressListenerCallbacks() throws IOException {
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
writer.setOutput(ImageIO.createImageOutputStream(buffer));
|
writer.setOutput(ImageIO.createImageOutputStream(buffer));
|
||||||
|
|
||||||
@@ -214,7 +225,7 @@ public abstract class ImageWriterAbstractTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMultipleAddIIOWriteProgressListenerCallbacks() throws IOException {
|
public void testMultipleAddIIOWriteProgressListenerCallbacks() throws IOException {
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
writer.setOutput(ImageIO.createImageOutputStream(buffer));
|
writer.setOutput(ImageIO.createImageOutputStream(buffer));
|
||||||
|
|
||||||
@@ -250,20 +261,20 @@ public abstract class ImageWriterAbstractTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRemoveIIOWriteProgressListenerNull() {
|
public void testRemoveIIOWriteProgressListenerNull() throws IOException {
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
writer.removeIIOWriteProgressListener(null);
|
writer.removeIIOWriteProgressListener(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRemoveIIOWriteProgressListenerNone() {
|
public void testRemoveIIOWriteProgressListenerNone() throws IOException {
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
writer.removeIIOWriteProgressListener(mock(IIOWriteProgressListener.class));
|
writer.removeIIOWriteProgressListener(mock(IIOWriteProgressListener.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRemoveIIOWriteProgressListener() throws IOException {
|
public void testRemoveIIOWriteProgressListener() throws IOException {
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
writer.setOutput(ImageIO.createImageOutputStream(buffer));
|
writer.setOutput(ImageIO.createImageOutputStream(buffer));
|
||||||
|
|
||||||
@@ -284,7 +295,7 @@ public abstract class ImageWriterAbstractTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRemoveIIOWriteProgressListenerMultiple() throws IOException {
|
public void testRemoveIIOWriteProgressListenerMultiple() throws IOException {
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
writer.setOutput(ImageIO.createImageOutputStream(buffer));
|
writer.setOutput(ImageIO.createImageOutputStream(buffer));
|
||||||
|
|
||||||
@@ -316,7 +327,7 @@ public abstract class ImageWriterAbstractTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRemoveAllIIOWriteProgressListeners() throws IOException {
|
public void testRemoveAllIIOWriteProgressListeners() throws IOException {
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
writer.setOutput(ImageIO.createImageOutputStream(buffer));
|
writer.setOutput(ImageIO.createImageOutputStream(buffer));
|
||||||
|
|
||||||
@@ -339,7 +350,7 @@ public abstract class ImageWriterAbstractTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRemoveAllIIOWriteProgressListenersMultiple() throws IOException {
|
public void testRemoveAllIIOWriteProgressListenersMultiple() throws IOException {
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
writer.setOutput(ImageIO.createImageOutputStream(buffer));
|
writer.setOutput(ImageIO.createImageOutputStream(buffer));
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
package com.twelvemonkeys.imageio.util;
|
package com.twelvemonkeys.imageio.util;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.color.ColorSpaces;
|
import com.twelvemonkeys.imageio.color.ColorSpaces;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import javax.imageio.ImageTypeSpecifier;
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
@@ -39,7 +40,8 @@ import java.awt.image.ComponentColorModel;
|
|||||||
import java.awt.image.DataBuffer;
|
import java.awt.image.DataBuffer;
|
||||||
import java.awt.image.PixelInterleavedSampleModel;
|
import java.awt.image.PixelInterleavedSampleModel;
|
||||||
|
|
||||||
import static org.hamcrest.core.Is.is;
|
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
public class UInt32ImageTypeSpecifierTest {
|
public class UInt32ImageTypeSpecifierTest {
|
||||||
@@ -55,13 +57,13 @@ public class UInt32ImageTypeSpecifierTest {
|
|||||||
assertEquals(1, spec.getNumComponents());
|
assertEquals(1, spec.getNumComponents());
|
||||||
assertEquals(32, spec.getBitsPerBand(0));
|
assertEquals(32, spec.getBitsPerBand(0));
|
||||||
|
|
||||||
assertThat(spec.getColorModel(), is(ComponentColorModel.class));
|
assertThat(spec.getColorModel(), instanceOf(ComponentColorModel.class));
|
||||||
assertFalse(spec.getColorModel().hasAlpha());
|
assertFalse(spec.getColorModel().hasAlpha());
|
||||||
assertFalse(spec.getColorModel().isAlphaPremultiplied());
|
assertFalse(spec.getColorModel().isAlphaPremultiplied());
|
||||||
assertEquals(1, spec.getColorModel().getNumComponents());
|
assertEquals(1, spec.getColorModel().getNumComponents());
|
||||||
assertEquals(1, spec.getColorModel().getNumColorComponents());
|
assertEquals(1, spec.getColorModel().getNumColorComponents());
|
||||||
|
|
||||||
assertThat(spec.getSampleModel(), is(PixelInterleavedSampleModel.class));
|
assertThat(spec.getSampleModel(), instanceOf(PixelInterleavedSampleModel.class));
|
||||||
assertEquals(1, spec.getSampleModel().getNumBands());
|
assertEquals(1, spec.getSampleModel().getNumBands());
|
||||||
assertEquals(1, spec.getSampleModel().getNumDataElements());
|
assertEquals(1, spec.getSampleModel().getNumDataElements());
|
||||||
}
|
}
|
||||||
@@ -74,13 +76,13 @@ public class UInt32ImageTypeSpecifierTest {
|
|||||||
assertEquals(32, spec.getBitsPerBand(0));
|
assertEquals(32, spec.getBitsPerBand(0));
|
||||||
assertEquals(32, spec.getBitsPerBand(1));
|
assertEquals(32, spec.getBitsPerBand(1));
|
||||||
|
|
||||||
assertThat(spec.getColorModel(), is(ComponentColorModel.class));
|
assertThat(spec.getColorModel(), instanceOf(ComponentColorModel.class));
|
||||||
assertTrue(spec.getColorModel().hasAlpha());
|
assertTrue(spec.getColorModel().hasAlpha());
|
||||||
assertFalse(spec.getColorModel().isAlphaPremultiplied());
|
assertFalse(spec.getColorModel().isAlphaPremultiplied());
|
||||||
assertEquals(2, spec.getColorModel().getNumComponents());
|
assertEquals(2, spec.getColorModel().getNumComponents());
|
||||||
assertEquals(1, spec.getColorModel().getNumColorComponents());
|
assertEquals(1, spec.getColorModel().getNumColorComponents());
|
||||||
|
|
||||||
assertThat(spec.getSampleModel(), is(PixelInterleavedSampleModel.class));
|
assertThat(spec.getSampleModel(), instanceOf(PixelInterleavedSampleModel.class));
|
||||||
assertEquals(2, spec.getSampleModel().getNumBands());
|
assertEquals(2, spec.getSampleModel().getNumBands());
|
||||||
assertEquals(2, spec.getSampleModel().getNumDataElements());
|
assertEquals(2, spec.getSampleModel().getNumDataElements());
|
||||||
}
|
}
|
||||||
@@ -95,13 +97,13 @@ public class UInt32ImageTypeSpecifierTest {
|
|||||||
assertEquals(32, spec.getBitsPerBand(1));
|
assertEquals(32, spec.getBitsPerBand(1));
|
||||||
assertEquals(32, spec.getBitsPerBand(2));
|
assertEquals(32, spec.getBitsPerBand(2));
|
||||||
|
|
||||||
assertThat(spec.getColorModel(), is(ComponentColorModel.class));
|
assertThat(spec.getColorModel(), instanceOf(ComponentColorModel.class));
|
||||||
assertFalse(spec.getColorModel().hasAlpha());
|
assertFalse(spec.getColorModel().hasAlpha());
|
||||||
assertFalse(spec.getColorModel().isAlphaPremultiplied());
|
assertFalse(spec.getColorModel().isAlphaPremultiplied());
|
||||||
assertEquals(3, spec.getColorModel().getNumComponents());
|
assertEquals(3, spec.getColorModel().getNumComponents());
|
||||||
assertEquals(3, spec.getColorModel().getNumColorComponents());
|
assertEquals(3, spec.getColorModel().getNumColorComponents());
|
||||||
|
|
||||||
assertThat(spec.getSampleModel(), is(PixelInterleavedSampleModel.class));
|
assertThat(spec.getSampleModel(), instanceOf(PixelInterleavedSampleModel.class));
|
||||||
assertEquals(3, spec.getSampleModel().getNumBands());
|
assertEquals(3, spec.getSampleModel().getNumBands());
|
||||||
assertEquals(3, spec.getSampleModel().getNumDataElements());
|
assertEquals(3, spec.getSampleModel().getNumDataElements());
|
||||||
}
|
}
|
||||||
@@ -116,13 +118,13 @@ public class UInt32ImageTypeSpecifierTest {
|
|||||||
assertEquals(32, spec.getBitsPerBand(2));
|
assertEquals(32, spec.getBitsPerBand(2));
|
||||||
assertEquals(32, spec.getBitsPerBand(3));
|
assertEquals(32, spec.getBitsPerBand(3));
|
||||||
|
|
||||||
assertThat(spec.getColorModel(), is(ComponentColorModel.class));
|
assertThat(spec.getColorModel(), instanceOf(ComponentColorModel.class));
|
||||||
assertTrue(spec.getColorModel().hasAlpha());
|
assertTrue(spec.getColorModel().hasAlpha());
|
||||||
assertFalse(spec.getColorModel().isAlphaPremultiplied());
|
assertFalse(spec.getColorModel().isAlphaPremultiplied());
|
||||||
assertEquals(4, spec.getColorModel().getNumComponents());
|
assertEquals(4, spec.getColorModel().getNumComponents());
|
||||||
assertEquals(3, spec.getColorModel().getNumColorComponents());
|
assertEquals(3, spec.getColorModel().getNumColorComponents());
|
||||||
|
|
||||||
assertThat(spec.getSampleModel(), is(PixelInterleavedSampleModel.class));
|
assertThat(spec.getSampleModel(), instanceOf(PixelInterleavedSampleModel.class));
|
||||||
assertEquals(4, spec.getSampleModel().getNumBands());
|
assertEquals(4, spec.getSampleModel().getNumBands());
|
||||||
assertEquals(4, spec.getSampleModel().getNumDataElements());
|
assertEquals(4, spec.getSampleModel().getNumDataElements());
|
||||||
}
|
}
|
||||||
@@ -137,13 +139,13 @@ public class UInt32ImageTypeSpecifierTest {
|
|||||||
assertEquals(32, spec.getBitsPerBand(2));
|
assertEquals(32, spec.getBitsPerBand(2));
|
||||||
assertEquals(32, spec.getBitsPerBand(3));
|
assertEquals(32, spec.getBitsPerBand(3));
|
||||||
|
|
||||||
assertThat(spec.getColorModel(), is(ComponentColorModel.class));
|
assertThat(spec.getColorModel(), instanceOf(ComponentColorModel.class));
|
||||||
assertTrue(spec.getColorModel().hasAlpha());
|
assertTrue(spec.getColorModel().hasAlpha());
|
||||||
assertTrue(spec.getColorModel().isAlphaPremultiplied());
|
assertTrue(spec.getColorModel().isAlphaPremultiplied());
|
||||||
assertEquals(4, spec.getColorModel().getNumComponents());
|
assertEquals(4, spec.getColorModel().getNumComponents());
|
||||||
assertEquals(3, spec.getColorModel().getNumColorComponents());
|
assertEquals(3, spec.getColorModel().getNumColorComponents());
|
||||||
|
|
||||||
assertThat(spec.getSampleModel(), is(PixelInterleavedSampleModel.class));
|
assertThat(spec.getSampleModel(), instanceOf(PixelInterleavedSampleModel.class));
|
||||||
assertEquals(4, spec.getSampleModel().getNumBands());
|
assertEquals(4, spec.getSampleModel().getNumBands());
|
||||||
assertEquals(4, spec.getSampleModel().getNumDataElements());
|
assertEquals(4, spec.getSampleModel().getNumDataElements());
|
||||||
}
|
}
|
||||||
@@ -159,13 +161,13 @@ public class UInt32ImageTypeSpecifierTest {
|
|||||||
assertEquals(32, spec.getBitsPerBand(2));
|
assertEquals(32, spec.getBitsPerBand(2));
|
||||||
assertEquals(32, spec.getBitsPerBand(3));
|
assertEquals(32, spec.getBitsPerBand(3));
|
||||||
|
|
||||||
assertThat(spec.getColorModel(), is(ComponentColorModel.class));
|
assertThat(spec.getColorModel(), instanceOf(ComponentColorModel.class));
|
||||||
assertFalse(spec.getColorModel().hasAlpha());
|
assertFalse(spec.getColorModel().hasAlpha());
|
||||||
assertFalse(spec.getColorModel().isAlphaPremultiplied());
|
assertFalse(spec.getColorModel().isAlphaPremultiplied());
|
||||||
assertEquals(4, spec.getColorModel().getNumComponents());
|
assertEquals(4, spec.getColorModel().getNumComponents());
|
||||||
assertEquals(4, spec.getColorModel().getNumColorComponents());
|
assertEquals(4, spec.getColorModel().getNumColorComponents());
|
||||||
|
|
||||||
assertThat(spec.getSampleModel(), is(PixelInterleavedSampleModel.class));
|
assertThat(spec.getSampleModel(), instanceOf(PixelInterleavedSampleModel.class));
|
||||||
assertEquals(4, spec.getSampleModel().getNumBands());
|
assertEquals(4, spec.getSampleModel().getNumBands());
|
||||||
assertEquals(4, spec.getSampleModel().getNumDataElements());
|
assertEquals(4, spec.getSampleModel().getNumDataElements());
|
||||||
}
|
}
|
||||||
@@ -181,13 +183,13 @@ public class UInt32ImageTypeSpecifierTest {
|
|||||||
assertEquals(32, spec.getBitsPerBand(3));
|
assertEquals(32, spec.getBitsPerBand(3));
|
||||||
assertEquals(32, spec.getBitsPerBand(4));
|
assertEquals(32, spec.getBitsPerBand(4));
|
||||||
|
|
||||||
assertThat(spec.getColorModel(), is(ComponentColorModel.class));
|
assertThat(spec.getColorModel(), instanceOf(ComponentColorModel.class));
|
||||||
assertTrue(spec.getColorModel().hasAlpha());
|
assertTrue(spec.getColorModel().hasAlpha());
|
||||||
assertFalse(spec.getColorModel().isAlphaPremultiplied());
|
assertFalse(spec.getColorModel().isAlphaPremultiplied());
|
||||||
assertEquals(5, spec.getColorModel().getNumComponents());
|
assertEquals(5, spec.getColorModel().getNumComponents());
|
||||||
assertEquals(4, spec.getColorModel().getNumColorComponents());
|
assertEquals(4, spec.getColorModel().getNumColorComponents());
|
||||||
|
|
||||||
assertThat(spec.getSampleModel(), is(PixelInterleavedSampleModel.class));
|
assertThat(spec.getSampleModel(), instanceOf(PixelInterleavedSampleModel.class));
|
||||||
assertEquals(5, spec.getSampleModel().getNumBands());
|
assertEquals(5, spec.getSampleModel().getNumBands());
|
||||||
assertEquals(5, spec.getSampleModel().getNumDataElements());
|
assertEquals(5, spec.getSampleModel().getNumDataElements());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.5</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>
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio-core</artifactId>
|
<artifactId>imageio-core</artifactId>
|
||||||
<type>test-jar</type>
|
<type>test-jar</type>
|
||||||
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
|||||||
@@ -46,26 +46,16 @@ import java.util.List;
|
|||||||
* @version $Id: TGAImageReaderTest.java,v 1.0 03.07.14 22:28 haraldk Exp$
|
* @version $Id: TGAImageReaderTest.java,v 1.0 03.07.14 22:28 haraldk Exp$
|
||||||
*/
|
*/
|
||||||
public class HDRImageReaderTest extends ImageReaderAbstractTest<HDRImageReader> {
|
public class HDRImageReaderTest extends ImageReaderAbstractTest<HDRImageReader> {
|
||||||
@Override
|
|
||||||
protected List<TestData> getTestData() {
|
|
||||||
return Arrays.asList(
|
|
||||||
new TestData(getClassLoaderResource("/hdr/memorial_o876.hdr"), new Dimension(512, 768))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ImageReaderSpi createProvider() {
|
protected ImageReaderSpi createProvider() {
|
||||||
return new HDRImageReaderSpi();
|
return new HDRImageReaderSpi();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Class<HDRImageReader> getReaderClass() {
|
protected List<TestData> getTestData() {
|
||||||
return HDRImageReader.class;
|
return Collections.singletonList(
|
||||||
}
|
new TestData(getClassLoaderResource("/hdr/memorial_o876.hdr"), new Dimension(512, 768))
|
||||||
|
);
|
||||||
@Override
|
|
||||||
protected HDRImageReader createReader() {
|
|
||||||
return new HDRImageReader(createProvider());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.twelvemonkeys.imageio.plugins.hdr.tonemap;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
|
||||||
|
public class DefaultToneMapperTest {
|
||||||
|
|
||||||
|
private final DefaultToneMapper mapper = new DefaultToneMapper();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMap0() {
|
||||||
|
float[] rgb = {0};
|
||||||
|
mapper.map(rgb);
|
||||||
|
assertArrayEquals(new float[]{0}, rgb, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMap1() {
|
||||||
|
float[] rgb = {1};
|
||||||
|
mapper.map(rgb);
|
||||||
|
assertArrayEquals(new float[]{0.5f}, rgb, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMapMax() {
|
||||||
|
float[] rgb = {Float.MAX_VALUE};
|
||||||
|
mapper.map(rgb);
|
||||||
|
assertArrayEquals(new float[]{1}, rgb, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.twelvemonkeys.imageio.plugins.hdr.tonemap;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
|
||||||
|
public class GammaToneMapperTest {
|
||||||
|
private final GammaToneMapper mapper = new GammaToneMapper();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMap0() {
|
||||||
|
float[] rgb = {0};
|
||||||
|
mapper.map(rgb);
|
||||||
|
assertArrayEquals(new float[]{0}, rgb, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMap1() {
|
||||||
|
float[] rgb = {1};
|
||||||
|
mapper.map(rgb);
|
||||||
|
assertArrayEquals(new float[]{0.5f}, rgb, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMap16() {
|
||||||
|
float[] rgb = {15.999999f};
|
||||||
|
mapper.map(rgb);
|
||||||
|
assertArrayEquals(new float[]{1}, rgb, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMapMax() {
|
||||||
|
float[] rgb = {Float.MAX_VALUE};
|
||||||
|
mapper.map(rgb);
|
||||||
|
assertArrayEquals(new float[]{1}, rgb, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package com.twelvemonkeys.imageio.plugins.hdr.tonemap;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
|
||||||
|
public class NullToneMapperTest {
|
||||||
|
private final NullToneMapper mapper = new NullToneMapper();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMap0() {
|
||||||
|
float[] rgb = {0};
|
||||||
|
mapper.map(rgb);
|
||||||
|
assertArrayEquals(new float[]{0}, rgb, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMap1() {
|
||||||
|
float[] rgb = {1};
|
||||||
|
mapper.map(rgb);
|
||||||
|
assertArrayEquals(new float[]{1}, rgb, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMapMax() {
|
||||||
|
float[] rgb = {Float.MAX_VALUE};
|
||||||
|
mapper.map(rgb);
|
||||||
|
assertArrayEquals(new float[]{Float.MAX_VALUE}, rgb, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.5</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>
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio-core</artifactId>
|
<artifactId>imageio-core</artifactId>
|
||||||
<type>test-jar</type>
|
<type>test-jar</type>
|
||||||
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -31,10 +31,10 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.icns;
|
package com.twelvemonkeys.imageio.plugins.icns;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
||||||
|
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import javax.imageio.ImageReader;
|
|
||||||
import javax.imageio.spi.ImageReaderSpi;
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -49,7 +49,12 @@ import java.util.List;
|
|||||||
* @author last modified by $Author: haraldk$
|
* @author last modified by $Author: haraldk$
|
||||||
* @version $Id: ICNSImageReaderTest.java,v 1.0 25.10.11 18:44 haraldk Exp$
|
* @version $Id: ICNSImageReaderTest.java,v 1.0 25.10.11 18:44 haraldk Exp$
|
||||||
*/
|
*/
|
||||||
public class ICNSImageReaderTest extends ImageReaderAbstractTest {
|
public class ICNSImageReaderTest extends ImageReaderAbstractTest<ICNSImageReader> {
|
||||||
|
@Override
|
||||||
|
protected ImageReaderSpi createProvider() {
|
||||||
|
return new ICNSImageReaderSpi();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<TestData> getTestData() {
|
protected List<TestData> getTestData() {
|
||||||
return Arrays.asList(
|
return Arrays.asList(
|
||||||
@@ -105,21 +110,6 @@ public class ICNSImageReaderTest extends ImageReaderAbstractTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ImageReaderSpi createProvider() {
|
|
||||||
return new ICNSImageReaderSpi();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ImageReader createReader() {
|
|
||||||
return new ICNSImageReader();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class getReaderClass() {
|
|
||||||
return ICNSImageReader.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<String> getFormatNames() {
|
protected List<String> getFormatNames() {
|
||||||
return Collections.singletonList("icns");
|
return Collections.singletonList("icns");
|
||||||
|
|||||||
@@ -31,11 +31,13 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.icns;
|
package com.twelvemonkeys.imageio.plugins.icns;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.util.ImageWriterAbstractTest;
|
import com.twelvemonkeys.imageio.util.ImageWriterAbstractTest;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import javax.imageio.IIOImage;
|
import javax.imageio.IIOImage;
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import javax.imageio.ImageWriter;
|
import javax.imageio.ImageWriter;
|
||||||
|
import javax.imageio.spi.ImageWriterSpi;
|
||||||
import javax.imageio.stream.ImageOutputStream;
|
import javax.imageio.stream.ImageOutputStream;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.RenderedImage;
|
import java.awt.image.RenderedImage;
|
||||||
@@ -53,13 +55,11 @@ import static org.junit.Assert.assertTrue;
|
|||||||
* @author last modified by $Author: harald.kuhr$
|
* @author last modified by $Author: harald.kuhr$
|
||||||
* @version $Id: ICNSImageWriterTest.java,v 1.0 25/08/2018 harald.kuhr Exp$
|
* @version $Id: ICNSImageWriterTest.java,v 1.0 25/08/2018 harald.kuhr Exp$
|
||||||
*/
|
*/
|
||||||
public class ICNSImageWriterTest extends ImageWriterAbstractTest {
|
public class ICNSImageWriterTest extends ImageWriterAbstractTest<ICNSImageWriter> {
|
||||||
|
|
||||||
private final ICNSImageWriterSpi provider = new ICNSImageWriterSpi();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ImageWriter createImageWriter() {
|
protected ImageWriterSpi createProvider() {
|
||||||
return provider.createWriterInstance(null);
|
return new ICNSImageWriterSpi();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -81,7 +81,7 @@ public class ICNSImageWriterTest extends ImageWriterAbstractTest {
|
|||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void testWriteNonSquare() throws IOException {
|
public void testWriteNonSquare() throws IOException {
|
||||||
// ICNS only supports square icons (except some arcane 16x12 we don't currently support)
|
// ICNS only supports square icons (except some arcane 16x12 we don't currently support)
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
try (ImageOutputStream stream = ImageIO.createImageOutputStream(new ByteArrayOutputStream())) {
|
try (ImageOutputStream stream = ImageIO.createImageOutputStream(new ByteArrayOutputStream())) {
|
||||||
|
|
||||||
writer.setOutput(stream);
|
writer.setOutput(stream);
|
||||||
@@ -97,7 +97,7 @@ public class ICNSImageWriterTest extends ImageWriterAbstractTest {
|
|||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void testWriteBadSize() throws IOException {
|
public void testWriteBadSize() throws IOException {
|
||||||
// ICNS only supports sizes in multiples of 2 (16, 32, 64, ..., 1024 + 48 and 96)
|
// ICNS only supports sizes in multiples of 2 (16, 32, 64, ..., 1024 + 48 and 96)
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
try (ImageOutputStream stream = ImageIO.createImageOutputStream(new ByteArrayOutputStream())) {
|
try (ImageOutputStream stream = ImageIO.createImageOutputStream(new ByteArrayOutputStream())) {
|
||||||
|
|
||||||
writer.setOutput(stream);
|
writer.setOutput(stream);
|
||||||
@@ -111,8 +111,8 @@ public class ICNSImageWriterTest extends ImageWriterAbstractTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSequencesSupported() {
|
public void testSequencesSupported() throws IOException {
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
try {
|
try {
|
||||||
assertTrue(writer.canWriteSequence());
|
assertTrue(writer.canWriteSequence());
|
||||||
}
|
}
|
||||||
@@ -124,7 +124,7 @@ public class ICNSImageWriterTest extends ImageWriterAbstractTest {
|
|||||||
@Test(expected = IllegalStateException.class)
|
@Test(expected = IllegalStateException.class)
|
||||||
public void testWriteSequenceNotStarted() throws IOException {
|
public void testWriteSequenceNotStarted() throws IOException {
|
||||||
// ICNS only supports sizes in multiples of 2 (16, 32, 64, ..., 1024 + 48 and 96)
|
// ICNS only supports sizes in multiples of 2 (16, 32, 64, ..., 1024 + 48 and 96)
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
try (ImageOutputStream stream = ImageIO.createImageOutputStream(new ByteArrayOutputStream())) {
|
try (ImageOutputStream stream = ImageIO.createImageOutputStream(new ByteArrayOutputStream())) {
|
||||||
|
|
||||||
writer.setOutput(stream);
|
writer.setOutput(stream);
|
||||||
@@ -141,7 +141,7 @@ public class ICNSImageWriterTest extends ImageWriterAbstractTest {
|
|||||||
@Test(expected = IllegalStateException.class)
|
@Test(expected = IllegalStateException.class)
|
||||||
public void testEndSequenceNotStarted() throws IOException {
|
public void testEndSequenceNotStarted() throws IOException {
|
||||||
// ICNS only supports sizes in multiples of 2 (16, 32, 64, ..., 1024 + 48 and 96)
|
// ICNS only supports sizes in multiples of 2 (16, 32, 64, ..., 1024 + 48 and 96)
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
try (ImageOutputStream stream = ImageIO.createImageOutputStream(new ByteArrayOutputStream())) {
|
try (ImageOutputStream stream = ImageIO.createImageOutputStream(new ByteArrayOutputStream())) {
|
||||||
|
|
||||||
writer.setOutput(stream);
|
writer.setOutput(stream);
|
||||||
@@ -155,7 +155,7 @@ public class ICNSImageWriterTest extends ImageWriterAbstractTest {
|
|||||||
@Test(expected = IllegalStateException.class)
|
@Test(expected = IllegalStateException.class)
|
||||||
public void testPrepareSequenceAlreadyStarted() throws IOException {
|
public void testPrepareSequenceAlreadyStarted() throws IOException {
|
||||||
// ICNS only supports sizes in multiples of 2 (16, 32, 64, ..., 1024 + 48 and 96)
|
// ICNS only supports sizes in multiples of 2 (16, 32, 64, ..., 1024 + 48 and 96)
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
try (ImageOutputStream stream = ImageIO.createImageOutputStream(new ByteArrayOutputStream())) {
|
try (ImageOutputStream stream = ImageIO.createImageOutputStream(new ByteArrayOutputStream())) {
|
||||||
|
|
||||||
writer.setOutput(stream);
|
writer.setOutput(stream);
|
||||||
@@ -169,7 +169,7 @@ public class ICNSImageWriterTest extends ImageWriterAbstractTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWriteSequence() throws IOException {
|
public void testWriteSequence() throws IOException {
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||||
|
|
||||||
try (ImageOutputStream stream = ImageIO.createImageOutputStream(output)) {
|
try (ImageOutputStream stream = ImageIO.createImageOutputStream(output)) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.5</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>
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio-core</artifactId>
|
<artifactId>imageio-core</artifactId>
|
||||||
<type>test-jar</type>
|
<type>test-jar</type>
|
||||||
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.iff;
|
package com.twelvemonkeys.imageio.plugins.iff;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
@@ -54,6 +55,12 @@ import static org.junit.Assert.*;
|
|||||||
* @version $Id: IFFImageReaderTestCase.java,v 1.0 Apr 1, 2008 10:39:17 PM haraldk Exp$
|
* @version $Id: IFFImageReaderTestCase.java,v 1.0 Apr 1, 2008 10:39:17 PM haraldk Exp$
|
||||||
*/
|
*/
|
||||||
public class IFFImageReaderTest extends ImageReaderAbstractTest<IFFImageReader> {
|
public class IFFImageReaderTest extends ImageReaderAbstractTest<IFFImageReader> {
|
||||||
|
@Override
|
||||||
|
protected ImageReaderSpi createProvider() {
|
||||||
|
return new IFFImageReaderSpi();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected List<TestData> getTestData() {
|
protected List<TestData> getTestData() {
|
||||||
return Arrays.asList(
|
return Arrays.asList(
|
||||||
// 32 bit - Ok
|
// 32 bit - Ok
|
||||||
@@ -85,22 +92,17 @@ public class IFFImageReaderTest extends ImageReaderAbstractTest<IFFImageReader>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ImageReaderSpi createProvider() {
|
@Override
|
||||||
return new IFFImageReaderSpi();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Class<IFFImageReader> getReaderClass() {
|
|
||||||
return IFFImageReader.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected List<String> getFormatNames() {
|
protected List<String> getFormatNames() {
|
||||||
return Collections.singletonList("iff");
|
return Collections.singletonList("iff");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected List<String> getSuffixes() {
|
protected List<String> getSuffixes() {
|
||||||
return Arrays.asList("iff", "ilbm", "ham", "ham8", "lbm");
|
return Arrays.asList("iff", "ilbm", "ham", "ham8", "lbm");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
protected List<String> getMIMETypes() {
|
protected List<String> getMIMETypes() {
|
||||||
return Arrays.asList("image/iff", "image/x-iff");
|
return Arrays.asList("image/iff", "image/x-iff");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,10 +32,12 @@ package com.twelvemonkeys.imageio.plugins.iff;
|
|||||||
|
|
||||||
import com.twelvemonkeys.image.MonochromeColorModel;
|
import com.twelvemonkeys.image.MonochromeColorModel;
|
||||||
import com.twelvemonkeys.imageio.util.ImageWriterAbstractTest;
|
import com.twelvemonkeys.imageio.util.ImageWriterAbstractTest;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import javax.imageio.ImageWriter;
|
import javax.imageio.ImageWriter;
|
||||||
|
import javax.imageio.spi.ImageWriterSpi;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import javax.imageio.stream.ImageOutputStream;
|
import javax.imageio.stream.ImageOutputStream;
|
||||||
import java.awt.color.ColorSpace;
|
import java.awt.color.ColorSpace;
|
||||||
@@ -56,12 +58,10 @@ import static org.junit.Assert.*;
|
|||||||
* @author last modified by $Author: haraldk$
|
* @author last modified by $Author: haraldk$
|
||||||
* @version $Id: JPEG2000ImageWriterTest.java,v 1.0 20.01.12 12:19 haraldk Exp$
|
* @version $Id: JPEG2000ImageWriterTest.java,v 1.0 20.01.12 12:19 haraldk Exp$
|
||||||
*/
|
*/
|
||||||
public class IFFImageWriterTest extends ImageWriterAbstractTest {
|
public class IFFImageWriterTest extends ImageWriterAbstractTest<IFFImageWriter> {
|
||||||
private final IFFImageWriterSpi provider = new IFFImageWriterSpi();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ImageWriter createImageWriter() {
|
protected ImageWriterSpi createProvider() {
|
||||||
return new IFFImageWriter(provider);
|
return new IFFImageWriterSpi();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -81,7 +81,7 @@ public class IFFImageWriterTest extends ImageWriterAbstractTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWriteReadCompare() throws IOException {
|
public void testWriteReadCompare() throws IOException {
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
|
|
||||||
List<? extends RenderedImage> testData = getTestData();
|
List<? extends RenderedImage> testData = getTestData();
|
||||||
|
|
||||||
@@ -116,9 +116,7 @@ public class IFFImageWriterTest extends ImageWriterAbstractTest {
|
|||||||
assertSameData(original, written);
|
assertSameData(original, written);
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
AssertionError fail = new AssertionError("Failure writing test data " + i + " " + e);
|
throw new AssertionError("Failure writing test data " + i + " " + e, e);
|
||||||
fail.initCause(e);
|
|
||||||
throw fail;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.5</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>
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio-core</artifactId>
|
<artifactId>imageio-core</artifactId>
|
||||||
<type>test-jar</type>
|
<type>test-jar</type>
|
||||||
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
|
|||||||
@@ -35,27 +35,27 @@ package com.twelvemonkeys.imageio.plugins.jpeg;
|
|||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
import javax.imageio.IIOException;
|
||||||
|
import javax.imageio.plugins.jpeg.JPEGHuffmanTable;
|
||||||
import java.io.DataInput;
|
import java.io.DataInput;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
final class HuffmanTable extends Segment {
|
final class HuffmanTable extends Segment {
|
||||||
|
|
||||||
private final int l[][][] = new int[4][2][16];
|
private final short[][][] l = new short[4][2][16];
|
||||||
private final int th[] = new int[4]; // 1: this table is present
|
private final short[][][][] v = new short[4][2][16][200]; // tables
|
||||||
final int v[][][][] = new int[4][2][16][200]; // tables
|
private final boolean[][] tc = new boolean[4][2]; // 1: this table is present
|
||||||
final int[][] tc = new int[4][2]; // 1: this table is present
|
|
||||||
|
|
||||||
static final int MSB = 0x80000000;
|
private static final int MSB = 0x80000000;
|
||||||
|
|
||||||
private HuffmanTable() {
|
private HuffmanTable() {
|
||||||
super(JPEG.DHT);
|
super(JPEG.DHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void buildHuffTables(final int[][][] HuffTab) throws IOException {
|
void buildHuffTables(final int[][][] huffTab) throws IOException {
|
||||||
for (int t = 0; t < 4; t++) {
|
for (int t = 0; t < 4; t++) {
|
||||||
for (int c = 0; c < 2; c++) {
|
for (int c = 0; c < 2; c++) {
|
||||||
if (tc[t][c] != 0) {
|
if (tc[t][c]) {
|
||||||
buildHuffTable(HuffTab[t][c], l[t][c], v[t][c]);
|
buildHuffTable(huffTab[t][c], l[t][c], v[t][c]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -68,7 +68,7 @@ final class HuffmanTable extends Segment {
|
|||||||
// V[i][j] Huffman Value (length=i)
|
// V[i][j] Huffman Value (length=i)
|
||||||
// Effect:
|
// Effect:
|
||||||
// build up HuffTab[t][c] using L and V.
|
// build up HuffTab[t][c] using L and V.
|
||||||
private void buildHuffTable(final int tab[], final int L[], final int V[][]) throws IOException {
|
private void buildHuffTable(final int[] tab, final short[] L, final short[][] V) throws IOException {
|
||||||
int temp = 256;
|
int temp = 256;
|
||||||
int k = 0;
|
int k = 0;
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@ final class HuffmanTable extends Segment {
|
|||||||
|
|
||||||
for (int t = 0; t < tc.length; t++) {
|
for (int t = 0; t < tc.length; t++) {
|
||||||
for (int c = 0; c < tc[t].length; c++) {
|
for (int c = 0; c < tc[t].length; c++) {
|
||||||
if (tc[t][c] != 0) {
|
if (tc[t][c]) {
|
||||||
if (builder.length() > 4) {
|
if (builder.length() > 4) {
|
||||||
builder.append(", ");
|
builder.append(", ");
|
||||||
}
|
}
|
||||||
@@ -149,11 +149,10 @@ final class HuffmanTable extends Segment {
|
|||||||
throw new IIOException("Unexpected JPEG Huffman Table class (> 2): " + c);
|
throw new IIOException("Unexpected JPEG Huffman Table class (> 2): " + c);
|
||||||
}
|
}
|
||||||
|
|
||||||
table.th[t] = 1;
|
table.tc[t][c] = true;
|
||||||
table.tc[t][c] = 1;
|
|
||||||
|
|
||||||
for (int i = 0; i < 16; i++) {
|
for (int i = 0; i < 16; i++) {
|
||||||
table.l[t][c][i] = data.readUnsignedByte();
|
table.l[t][c][i] = (short) data.readUnsignedByte();
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +161,7 @@ final class HuffmanTable extends Segment {
|
|||||||
if (count > length) {
|
if (count > length) {
|
||||||
throw new IIOException("JPEG Huffman Table format error");
|
throw new IIOException("JPEG Huffman Table format error");
|
||||||
}
|
}
|
||||||
table.v[t][c][i][j] = data.readUnsignedByte();
|
table.v[t][c][i][j] = (short) data.readUnsignedByte();
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,4 +173,41 @@ final class HuffmanTable extends Segment {
|
|||||||
|
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isPresent(int tableId, int tableClass) {
|
||||||
|
return tc[tableId][tableClass];
|
||||||
|
}
|
||||||
|
|
||||||
|
private short[] lengths(int tableId, int tableClass) {
|
||||||
|
// TODO: Consider stripping the 0s?
|
||||||
|
return l[tableId][tableClass];
|
||||||
|
}
|
||||||
|
|
||||||
|
private short[] tables(int tableId, int tableClass) {
|
||||||
|
// Find sum of lengths
|
||||||
|
short[] lengths = lengths(tableId, tableClass);
|
||||||
|
|
||||||
|
int sumOfLengths = 0;
|
||||||
|
for (int length : lengths) {
|
||||||
|
sumOfLengths += length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flatten the tables
|
||||||
|
short[] tables = new short[sumOfLengths];
|
||||||
|
|
||||||
|
int pos = 0;
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
short[] table = v[tableId][tableClass][i];
|
||||||
|
short length = lengths[i];
|
||||||
|
|
||||||
|
System.arraycopy(table, 0, tables, pos, length);
|
||||||
|
pos += length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tables;
|
||||||
|
}
|
||||||
|
|
||||||
|
JPEGHuffmanTable toNativeTable(int tableId, int tableClass) {
|
||||||
|
return new JPEGHuffmanTable(lengths(tableId, tableClass), tables(tableId, tableClass));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ final class JFXXThumbnailReader extends ThumbnailReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cachedThumbnail = pixelsExposed ? null : new SoftReference<BufferedImage>(thumbnail);
|
cachedThumbnail = pixelsExposed ? null : new SoftReference<>(thumbnail);
|
||||||
|
|
||||||
return thumbnail;
|
return thumbnail;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,10 +30,16 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.jpeg;
|
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.AbstractMetadata;
|
import com.twelvemonkeys.imageio.AbstractMetadata;
|
||||||
|
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.tiff.TIFF;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
import javax.imageio.metadata.IIOMetadataNode;
|
import javax.imageio.metadata.IIOMetadataNode;
|
||||||
|
import java.awt.color.ICC_Profile;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,31 +51,89 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
class JPEGImage10Metadata extends AbstractMetadata {
|
class JPEGImage10Metadata extends AbstractMetadata {
|
||||||
|
|
||||||
// TODO: Clean up. Consider just making the meta data classes we were trying to avoid in the first place....
|
/**
|
||||||
|
* Native metadata format name
|
||||||
|
*/
|
||||||
|
static final String JAVAX_IMAGEIO_JPEG_IMAGE_1_0 = "javax_imageio_jpeg_image_1.0";
|
||||||
|
|
||||||
|
// TODO: Create our own native format, which is simply markerSequence from the Sun format, with the segments as-is, in sequence...
|
||||||
|
// + add special case for app segments, containing appXX + identifier (ie. <app0JFIF /> to <app0 identifier="JFIF" /> or <app app="0" identifier="JFIF" />
|
||||||
|
|
||||||
private final List<Segment> segments;
|
private final List<Segment> segments;
|
||||||
|
|
||||||
JPEGImage10Metadata(List<Segment> segments) {
|
private final Frame frame;
|
||||||
super(true, JPEGImage10MetadataCleaner.JAVAX_IMAGEIO_JPEG_IMAGE_1_0, null, null, null);
|
private final JFIF jfif;
|
||||||
|
private final AdobeDCT adobeDCT;
|
||||||
|
private final JFXX jfxx;
|
||||||
|
private final ICC_Profile embeddedICCProfile;
|
||||||
|
|
||||||
|
private final CompoundDirectory exif;
|
||||||
|
|
||||||
|
// TODO: Consider moving all the metadata stuff from the reader, over here...
|
||||||
|
JPEGImage10Metadata(final List<Segment> segments, Frame frame, JFIF jfif, JFXX jfxx, ICC_Profile embeddedICCProfile, AdobeDCT adobeDCT, final CompoundDirectory exif) {
|
||||||
|
super(true, JAVAX_IMAGEIO_JPEG_IMAGE_1_0, null, null, null);
|
||||||
|
|
||||||
this.segments = segments;
|
this.segments = segments;
|
||||||
|
this.frame = frame;
|
||||||
|
this.jfif = jfif;
|
||||||
|
this.adobeDCT = adobeDCT;
|
||||||
|
this.jfxx = jfxx;
|
||||||
|
this.embeddedICCProfile = embeddedICCProfile;
|
||||||
|
this.exif = exif;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Node getNativeTree() {
|
protected Node getNativeTree() {
|
||||||
IIOMetadataNode root = new IIOMetadataNode(JPEGImage10MetadataCleaner.JAVAX_IMAGEIO_JPEG_IMAGE_1_0);
|
IIOMetadataNode root = new IIOMetadataNode(JAVAX_IMAGEIO_JPEG_IMAGE_1_0);
|
||||||
|
|
||||||
IIOMetadataNode jpegVariety = new IIOMetadataNode("JPEGvariety");
|
IIOMetadataNode jpegVariety = new IIOMetadataNode("JPEGvariety");
|
||||||
root.appendChild(jpegVariety);
|
boolean isJFIF = jfif != null;
|
||||||
// TODO: If we have JFIF, append in JPEGvariety, but can't happen for lossless
|
if (isJFIF) {
|
||||||
|
IIOMetadataNode app0JFIF = new IIOMetadataNode("app0JFIF");
|
||||||
|
app0JFIF.setAttribute("majorVersion", Integer.toString(jfif.majorVersion));
|
||||||
|
app0JFIF.setAttribute("minorVersion", Integer.toString(jfif.minorVersion));
|
||||||
|
|
||||||
|
app0JFIF.setAttribute("resUnits", Integer.toString(jfif.units));
|
||||||
|
app0JFIF.setAttribute("Xdensity", Integer.toString(jfif.xDensity));
|
||||||
|
app0JFIF.setAttribute("Ydensity", Integer.toString(jfif.yDensity));
|
||||||
|
|
||||||
|
app0JFIF.setAttribute("thumbWidth", Integer.toString(jfif.xThumbnail));
|
||||||
|
app0JFIF.setAttribute("thumbHeight", Integer.toString(jfif.yThumbnail));
|
||||||
|
|
||||||
|
jpegVariety.appendChild(app0JFIF);
|
||||||
|
|
||||||
|
// Due to format oddity, add JFXX and app2ICC as subnodes here...
|
||||||
|
// ...and ignore them below, if added...
|
||||||
|
apendJFXX(app0JFIF);
|
||||||
|
appendICCProfile(app0JFIF);
|
||||||
|
}
|
||||||
|
|
||||||
|
root.appendChild(jpegVariety);
|
||||||
|
|
||||||
|
appendMarkerSequence(root, segments, isJFIF);
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendMarkerSequence(IIOMetadataNode root, List<Segment> segments, boolean isJFIF) {
|
||||||
IIOMetadataNode markerSequence = new IIOMetadataNode("markerSequence");
|
IIOMetadataNode markerSequence = new IIOMetadataNode("markerSequence");
|
||||||
root.appendChild(markerSequence);
|
root.appendChild(markerSequence);
|
||||||
|
|
||||||
for (Segment segment : segments)
|
for (Segment segment : segments)
|
||||||
switch (segment.marker) {
|
switch (segment.marker) {
|
||||||
// SOF3 is the only one supported by now
|
case JPEG.SOF0:
|
||||||
|
case JPEG.SOF1:
|
||||||
|
case JPEG.SOF2:
|
||||||
case JPEG.SOF3:
|
case JPEG.SOF3:
|
||||||
|
case JPEG.SOF5:
|
||||||
|
case JPEG.SOF6:
|
||||||
|
case JPEG.SOF7:
|
||||||
|
case JPEG.SOF9:
|
||||||
|
case JPEG.SOF10:
|
||||||
|
case JPEG.SOF11:
|
||||||
|
case JPEG.SOF13:
|
||||||
|
case JPEG.SOF14:
|
||||||
|
case JPEG.SOF15:
|
||||||
Frame sofSegment = (Frame) segment;
|
Frame sofSegment = (Frame) segment;
|
||||||
|
|
||||||
IIOMetadataNode sof = new IIOMetadataNode("sof");
|
IIOMetadataNode sof = new IIOMetadataNode("sof");
|
||||||
@@ -96,13 +160,13 @@ class JPEGImage10Metadata extends AbstractMetadata {
|
|||||||
HuffmanTable huffmanTable = (HuffmanTable) segment;
|
HuffmanTable huffmanTable = (HuffmanTable) segment;
|
||||||
IIOMetadataNode dht = new IIOMetadataNode("dht");
|
IIOMetadataNode dht = new IIOMetadataNode("dht");
|
||||||
|
|
||||||
// Uses fixed tables...
|
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
for (int j = 0; j < 2; j++) {
|
for (int c = 0; c < 2; c++) {
|
||||||
if (huffmanTable.tc[i][j] != 0) {
|
if (huffmanTable.isPresent(i, c)) {
|
||||||
IIOMetadataNode dhtable = new IIOMetadataNode("dhtable");
|
IIOMetadataNode dhtable = new IIOMetadataNode("dhtable");
|
||||||
dhtable.setAttribute("class", String.valueOf(j));
|
dhtable.setAttribute("class", String.valueOf(c));
|
||||||
dhtable.setAttribute("htableId", String.valueOf(i));
|
dhtable.setAttribute("htableId", String.valueOf(i));
|
||||||
|
dhtable.setUserObject(huffmanTable.toNativeTable(i, c));
|
||||||
dht.appendChild(dhtable);
|
dht.appendChild(dhtable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,8 +176,28 @@ class JPEGImage10Metadata extends AbstractMetadata {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case JPEG.DQT:
|
case JPEG.DQT:
|
||||||
markerSequence.appendChild(new IIOMetadataNode("dqt"));
|
QuantizationTable quantizationTable = (QuantizationTable) segment;
|
||||||
// TODO:
|
IIOMetadataNode dqt = new IIOMetadataNode("dqt");
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (quantizationTable.isPresent(i)) {
|
||||||
|
IIOMetadataNode dqtable = new IIOMetadataNode("dqtable");
|
||||||
|
dqtable.setAttribute("elementPrecision", quantizationTable.precision(i) != 16 ? "0" : "1"); // 0 = 8 bits, 1 = 16 bits
|
||||||
|
dqtable.setAttribute("qtableId", Integer.toString(i));
|
||||||
|
dqtable.setUserObject(quantizationTable.toNativeTable(i));
|
||||||
|
dqt.appendChild(dqtable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
markerSequence.appendChild(dqt);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JPEG.DRI:
|
||||||
|
RestartInterval restartInterval = (RestartInterval) segment;
|
||||||
|
IIOMetadataNode dri = new IIOMetadataNode("dri");
|
||||||
|
dri.setAttribute("interval", Integer.toString(restartInterval.interval));
|
||||||
|
markerSequence.appendChild(dri);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JPEG.SOS:
|
case JPEG.SOS:
|
||||||
@@ -144,6 +228,25 @@ class JPEGImage10Metadata extends AbstractMetadata {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case JPEG.APP0:
|
||||||
|
if (segment instanceof JFIF) {
|
||||||
|
// Either already added, or we'll ignore it anyway...
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (isJFIF && segment instanceof JFXX) {
|
||||||
|
// Already added
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Else, fall through to unknown segment
|
||||||
|
|
||||||
|
case JPEG.APP2:
|
||||||
|
if (isJFIF && segment instanceof ICCProfile) {
|
||||||
|
// Already added
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Else, fall through to unknown segment
|
||||||
|
|
||||||
case JPEG.APP14:
|
case JPEG.APP14:
|
||||||
if (segment instanceof AdobeDCT) {
|
if (segment instanceof AdobeDCT) {
|
||||||
AdobeDCT adobe = (AdobeDCT) segment;
|
AdobeDCT adobe = (AdobeDCT) segment;
|
||||||
@@ -165,32 +268,149 @@ class JPEGImage10Metadata extends AbstractMetadata {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return root;
|
private void appendICCProfile(IIOMetadataNode app0JFIF) {
|
||||||
|
if (embeddedICCProfile != null) {
|
||||||
|
IIOMetadataNode app2ICC = new IIOMetadataNode("app2ICC");
|
||||||
|
app2ICC.setUserObject(embeddedICCProfile);
|
||||||
|
|
||||||
|
app0JFIF.appendChild(app2ICC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void apendJFXX(IIOMetadataNode app0JFIF) {
|
||||||
|
if (jfxx != null) {
|
||||||
|
IIOMetadataNode jfxxNode = new IIOMetadataNode("JFXX");
|
||||||
|
app0JFIF.appendChild(jfxxNode);
|
||||||
|
|
||||||
|
IIOMetadataNode app0JFXX = new IIOMetadataNode("app0JFXX");
|
||||||
|
app0JFXX.setAttribute("extensionCode", Integer.toString(jfxx.extensionCode));
|
||||||
|
jfxxNode.appendChild(app0JFXX);
|
||||||
|
|
||||||
|
switch (jfxx.extensionCode) {
|
||||||
|
case JFXX.JPEG:
|
||||||
|
IIOMetadataNode thumbJPEG = new IIOMetadataNode("JFIFthumbJPEG");
|
||||||
|
thumbJPEG.appendChild(new IIOMetadataNode("markerSequence"));
|
||||||
|
// TODO: Insert segments in marker sequence...
|
||||||
|
// List<JPEGSegment> segments = JPEGSegmentUtil.readSegments(new ByteArrayImageInputStream(jfxx.thumbnail), JPEGSegmentUtil.ALL_SEGMENTS);
|
||||||
|
// Convert to Segment as in JPEGImageReader...
|
||||||
|
// appendMarkerSequence(thumbJPEG, segments, false);
|
||||||
|
|
||||||
|
app0JFXX.appendChild(thumbJPEG);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JFXX.INDEXED:
|
||||||
|
IIOMetadataNode thumbPalette = new IIOMetadataNode("JFIFthumbPalette");
|
||||||
|
thumbPalette.setAttribute("thumbWidth", Integer.toString(jfxx.thumbnail[0] & 0xFF));
|
||||||
|
thumbPalette.setAttribute("thumbHeight", Integer.toString(jfxx.thumbnail[1] & 0xFF));
|
||||||
|
app0JFXX.appendChild(thumbPalette);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JFXX.RGB:
|
||||||
|
IIOMetadataNode thumbRGB = new IIOMetadataNode("JFIFthumbRGB");
|
||||||
|
thumbRGB.setAttribute("thumbWidth", Integer.toString(jfxx.thumbnail[0] & 0xFF));
|
||||||
|
thumbRGB.setAttribute("thumbHeight", Integer.toString(jfxx.thumbnail[1] & 0xFF));
|
||||||
|
app0JFXX.appendChild(thumbRGB);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IIOMetadataNode getStandardChromaNode() {
|
protected IIOMetadataNode getStandardChromaNode() {
|
||||||
IIOMetadataNode chroma = new IIOMetadataNode("Chroma");
|
IIOMetadataNode chroma = new IIOMetadataNode("Chroma");
|
||||||
|
|
||||||
for (Segment segment : segments) {
|
IIOMetadataNode colorSpaceType = new IIOMetadataNode("ColorSpaceType");
|
||||||
if (segment instanceof Frame) {
|
colorSpaceType.setAttribute("name", getColorSpaceType());
|
||||||
Frame sofSegment = (Frame) segment;
|
chroma.appendChild(colorSpaceType);
|
||||||
IIOMetadataNode colorSpaceType = new IIOMetadataNode("ColorSpaceType");
|
|
||||||
colorSpaceType.setAttribute("name", sofSegment.componentsInFrame() == 1 ? "GRAY" : "RGB"); // TODO YCC, YCCK, CMYK etc
|
|
||||||
chroma.appendChild(colorSpaceType);
|
|
||||||
|
|
||||||
IIOMetadataNode numChannels = new IIOMetadataNode("NumChannels");
|
IIOMetadataNode numChannels = new IIOMetadataNode("NumChannels");
|
||||||
numChannels.setAttribute("value", String.valueOf(sofSegment.componentsInFrame()));
|
numChannels.setAttribute("value", String.valueOf(frame.componentsInFrame()));
|
||||||
chroma.appendChild(numChannels);
|
chroma.appendChild(numChannels);
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return chroma;
|
return chroma;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getColorSpaceType() {
|
||||||
|
try {
|
||||||
|
JPEGColorSpace csType = JPEGImageReader.getSourceCSType(jfif, adobeDCT, frame);
|
||||||
|
|
||||||
|
switch (csType) {
|
||||||
|
case Gray:
|
||||||
|
case GrayA:
|
||||||
|
return "GRAY";
|
||||||
|
case YCbCr:
|
||||||
|
case YCbCrA:
|
||||||
|
return "YCbCr";
|
||||||
|
case RGB:
|
||||||
|
case RGBA:
|
||||||
|
return "RGB";
|
||||||
|
case PhotoYCC:
|
||||||
|
case PhotoYCCA:
|
||||||
|
return "PhotoYCC";
|
||||||
|
case YCCK:
|
||||||
|
return "YCCK";
|
||||||
|
case CMYK:
|
||||||
|
return "CMYK";
|
||||||
|
default:
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IIOException ignore) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return Integer.toString(frame.componentsInFrame(), 16) + "CLR";
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasAlpha() {
|
||||||
|
try {
|
||||||
|
JPEGColorSpace csType = JPEGImageReader.getSourceCSType(jfif, adobeDCT, frame);
|
||||||
|
|
||||||
|
switch (csType) {
|
||||||
|
case GrayA:
|
||||||
|
case YCbCrA:
|
||||||
|
case RGBA:
|
||||||
|
case PhotoYCCA:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IIOException ignore) {
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isLossess() {
|
||||||
|
switch (frame.marker) {
|
||||||
|
case JPEG.SOF3:
|
||||||
|
case JPEG.SOF7:
|
||||||
|
case JPEG.SOF11:
|
||||||
|
case JPEG.SOF15:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IIOMetadataNode getStandardTransparencyNode() {
|
||||||
|
if (hasAlpha()) {
|
||||||
|
IIOMetadataNode transparency = new IIOMetadataNode("Transparency");
|
||||||
|
|
||||||
|
IIOMetadataNode alpha = new IIOMetadataNode("Alpha");
|
||||||
|
alpha.setAttribute("value", "nonpremultipled");
|
||||||
|
transparency.appendChild(alpha);
|
||||||
|
|
||||||
|
return transparency;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IIOMetadataNode getStandardCompressionNode() {
|
protected IIOMetadataNode getStandardCompressionNode() {
|
||||||
IIOMetadataNode compression = new IIOMetadataNode("Compression");
|
IIOMetadataNode compression = new IIOMetadataNode("Compression");
|
||||||
@@ -200,7 +420,7 @@ class JPEGImage10Metadata extends AbstractMetadata {
|
|||||||
compression.appendChild(compressionTypeName);
|
compression.appendChild(compressionTypeName);
|
||||||
|
|
||||||
IIOMetadataNode lossless = new IIOMetadataNode("Lossless");
|
IIOMetadataNode lossless = new IIOMetadataNode("Lossless");
|
||||||
lossless.setAttribute("value", "TRUE"); // TODO: For lossless only
|
lossless.setAttribute("value", isLossess() ? "TRUE" : "FALSE");
|
||||||
compression.appendChild(lossless);
|
compression.appendChild(lossless);
|
||||||
|
|
||||||
IIOMetadataNode numProgressiveScans = new IIOMetadataNode("NumProgressiveScans");
|
IIOMetadataNode numProgressiveScans = new IIOMetadataNode("NumProgressiveScans");
|
||||||
@@ -215,12 +435,67 @@ class JPEGImage10Metadata extends AbstractMetadata {
|
|||||||
IIOMetadataNode dimension = new IIOMetadataNode("Dimension");
|
IIOMetadataNode dimension = new IIOMetadataNode("Dimension");
|
||||||
|
|
||||||
IIOMetadataNode imageOrientation = new IIOMetadataNode("ImageOrientation");
|
IIOMetadataNode imageOrientation = new IIOMetadataNode("ImageOrientation");
|
||||||
imageOrientation.setAttribute("value", "normal"); // TODO
|
imageOrientation.setAttribute("value", getExifOrientation(exif));
|
||||||
dimension.appendChild(imageOrientation);
|
dimension.appendChild(imageOrientation);
|
||||||
|
|
||||||
|
if (jfif != null) {
|
||||||
|
// Aspect ratio
|
||||||
|
float xDensity = Math.max(1, jfif.xDensity);
|
||||||
|
float yDensity = Math.max(1, jfif.yDensity);
|
||||||
|
float aspectRatio = jfif.units == 0 ? xDensity / yDensity : yDensity / xDensity;
|
||||||
|
|
||||||
|
IIOMetadataNode pixelAspectRatio = new IIOMetadataNode("PixelAspectRatio");
|
||||||
|
pixelAspectRatio.setAttribute("value", Float.toString(aspectRatio));
|
||||||
|
dimension.insertBefore(pixelAspectRatio, imageOrientation); // Keep order
|
||||||
|
|
||||||
|
if (jfif.units != 0) {
|
||||||
|
// Pixel size
|
||||||
|
float scale = jfif.units == 1 ? 25.4F : 10.0F; // DPI or DPcm
|
||||||
|
|
||||||
|
IIOMetadataNode horizontalPixelSize = new IIOMetadataNode("HorizontalPixelSize");
|
||||||
|
horizontalPixelSize.setAttribute("value", Float.toString(scale / xDensity));
|
||||||
|
dimension.appendChild(horizontalPixelSize);
|
||||||
|
|
||||||
|
IIOMetadataNode verticalPixelSize = new IIOMetadataNode("VerticalPixelSize");
|
||||||
|
verticalPixelSize.setAttribute("value", Float.toString(scale / yDensity));
|
||||||
|
dimension.appendChild(verticalPixelSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return dimension;
|
return dimension;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getExifOrientation(Directory exif) {
|
||||||
|
if (exif != null) {
|
||||||
|
Entry orientationEntry = exif.getEntryById(TIFF.TAG_ORIENTATION);
|
||||||
|
|
||||||
|
if (orientationEntry != null) {
|
||||||
|
switch (((Number) orientationEntry.getValue()).intValue()) {
|
||||||
|
case 2:
|
||||||
|
return "FlipH";
|
||||||
|
case 3:
|
||||||
|
return "Rotate180";
|
||||||
|
case 4:
|
||||||
|
return "FlipV";
|
||||||
|
case 5:
|
||||||
|
return "FlipVRotate90";
|
||||||
|
case 6:
|
||||||
|
return "Rotate270";
|
||||||
|
case 7:
|
||||||
|
return "FlipHRotate90";
|
||||||
|
case 8:
|
||||||
|
return "Rotate90";
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
default:
|
||||||
|
// Fall-through
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Normal";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IIOMetadataNode getStandardTextNode() {
|
protected IIOMetadataNode getStandardTextNode() {
|
||||||
IIOMetadataNode text = new IIOMetadataNode("Text");
|
IIOMetadataNode text = new IIOMetadataNode("Text");
|
||||||
@@ -235,6 +510,10 @@ class JPEGImage10Metadata extends AbstractMetadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Add the following from Exif (as in TIFFMetadata)
|
||||||
|
// DocumentName, ImageDescription, Make, Model, PageName, Software, Artist, HostComputer, InkNames, Copyright:
|
||||||
|
// /Text/TextEntry@keyword = field name, /Text/TextEntry@value = field value.
|
||||||
|
|
||||||
return text.hasChildNodes() ? text : null;
|
return text.hasChildNodes() ? text : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,11 +52,6 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
final class JPEGImage10MetadataCleaner {
|
final class JPEGImage10MetadataCleaner {
|
||||||
|
|
||||||
/**
|
|
||||||
* Native metadata format name
|
|
||||||
*/
|
|
||||||
static final String JAVAX_IMAGEIO_JPEG_IMAGE_1_0 = "javax_imageio_jpeg_image_1.0";
|
|
||||||
|
|
||||||
private final JPEGImageReader reader;
|
private final JPEGImageReader reader;
|
||||||
|
|
||||||
JPEGImage10MetadataCleaner(final JPEGImageReader reader) {
|
JPEGImage10MetadataCleaner(final JPEGImageReader reader) {
|
||||||
@@ -93,7 +88,7 @@ final class JPEGImage10MetadataCleaner {
|
|||||||
the version to the method/constructor used to obtain an IIOMetadata object.)
|
the version to the method/constructor used to obtain an IIOMetadata object.)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
IIOMetadataNode tree = (IIOMetadataNode) imageMetadata.getAsTree(JAVAX_IMAGEIO_JPEG_IMAGE_1_0);
|
IIOMetadataNode tree = (IIOMetadataNode) imageMetadata.getAsTree(JPEGImage10Metadata.JAVAX_IMAGEIO_JPEG_IMAGE_1_0);
|
||||||
IIOMetadataNode jpegVariety = (IIOMetadataNode) tree.getElementsByTagName("JPEGvariety").item(0);
|
IIOMetadataNode jpegVariety = (IIOMetadataNode) tree.getElementsByTagName("JPEGvariety").item(0);
|
||||||
IIOMetadataNode markerSequence = (IIOMetadataNode) tree.getElementsByTagName("markerSequence").item(0);
|
IIOMetadataNode markerSequence = (IIOMetadataNode) tree.getElementsByTagName("markerSequence").item(0);
|
||||||
|
|
||||||
@@ -145,7 +140,7 @@ final class JPEGImage10MetadataCleaner {
|
|||||||
jfifThumb = new IIOMetadataNode("JFIFthumbJPEG");
|
jfifThumb = new IIOMetadataNode("JFIFthumbJPEG");
|
||||||
// Contains it's own "markerSequence" with full DHT, DQT, SOF etc...
|
// Contains it's own "markerSequence" with full DHT, DQT, SOF etc...
|
||||||
IIOMetadata thumbMeta = thumbnailReader.readMetadata();
|
IIOMetadata thumbMeta = thumbnailReader.readMetadata();
|
||||||
Node thumbTree = thumbMeta.getAsTree(JAVAX_IMAGEIO_JPEG_IMAGE_1_0);
|
Node thumbTree = thumbMeta.getAsTree(JPEGImage10Metadata.JAVAX_IMAGEIO_JPEG_IMAGE_1_0);
|
||||||
jfifThumb.appendChild(thumbTree.getLastChild());
|
jfifThumb.appendChild(thumbTree.getLastChild());
|
||||||
app0JFXX.appendChild(jfifThumb);
|
app0JFXX.appendChild(jfifThumb);
|
||||||
break;
|
break;
|
||||||
@@ -307,11 +302,11 @@ final class JPEGImage10MetadataCleaner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
imageMetadata.setFromTree(JAVAX_IMAGEIO_JPEG_IMAGE_1_0, tree);
|
imageMetadata.setFromTree(JPEGImage10Metadata.JAVAX_IMAGEIO_JPEG_IMAGE_1_0, tree);
|
||||||
}
|
}
|
||||||
catch (IIOInvalidTreeException e) {
|
catch (IIOInvalidTreeException e) {
|
||||||
if (JPEGImageReader.DEBUG) {
|
if (JPEGImageReader.DEBUG) {
|
||||||
new XMLSerializer(System.out, System.getProperty("file.encoding")).serialize(imageMetadata.getAsTree(JAVAX_IMAGEIO_JPEG_IMAGE_1_0), false);
|
new XMLSerializer(System.out, System.getProperty("file.encoding")).serialize(imageMetadata.getAsTree(JPEGImage10Metadata.JAVAX_IMAGEIO_JPEG_IMAGE_1_0), false);
|
||||||
System.out.println("-- 8< --");
|
System.out.println("-- 8< --");
|
||||||
new XMLSerializer(System.out, System.getProperty("file.encoding")).serialize(tree, false);
|
new XMLSerializer(System.out, System.getProperty("file.encoding")).serialize(tree, false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegment;
|
|||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegmentUtil;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegmentUtil;
|
||||||
import com.twelvemonkeys.imageio.metadata.tiff.TIFF;
|
import com.twelvemonkeys.imageio.metadata.tiff.TIFF;
|
||||||
import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader;
|
import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader;
|
||||||
import com.twelvemonkeys.imageio.stream.BufferedImageInputStream;
|
|
||||||
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
||||||
import com.twelvemonkeys.imageio.stream.SubImageInputStream;
|
import com.twelvemonkeys.imageio.stream.SubImageInputStream;
|
||||||
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
||||||
@@ -57,13 +56,13 @@ import javax.imageio.metadata.IIOMetadataFormatImpl;
|
|||||||
import javax.imageio.metadata.IIOMetadataNode;
|
import javax.imageio.metadata.IIOMetadataNode;
|
||||||
import javax.imageio.spi.ImageReaderSpi;
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import javax.imageio.stream.MemoryCacheImageInputStream;
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.color.ColorSpace;
|
import java.awt.color.ColorSpace;
|
||||||
import java.awt.color.ICC_ColorSpace;
|
import java.awt.color.ICC_ColorSpace;
|
||||||
import java.awt.color.ICC_Profile;
|
import java.awt.color.ICC_Profile;
|
||||||
import java.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.*;
|
||||||
|
|
||||||
@@ -113,9 +112,6 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
/** Internal constant for referring all APP segments */
|
/** Internal constant for referring all APP segments */
|
||||||
static final int ALL_APP_MARKERS = -1;
|
static final int ALL_APP_MARKERS = -1;
|
||||||
|
|
||||||
/** Segment identifiers for the JPEG segments we care about reading. */
|
|
||||||
private static final Map<Integer, List<String>> SEGMENT_IDENTIFIERS = JPEGSegmentUtil.ALL_SEGMENTS;
|
|
||||||
|
|
||||||
/** Our JPEG reading delegate */
|
/** Our JPEG reading delegate */
|
||||||
private final ImageReader delegate;
|
private final ImageReader delegate;
|
||||||
|
|
||||||
@@ -126,13 +122,11 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
private ImageReader thumbnailReader;
|
private ImageReader thumbnailReader;
|
||||||
private List<ThumbnailReader> thumbnails;
|
private List<ThumbnailReader> thumbnails;
|
||||||
|
|
||||||
private JPEGImage10MetadataCleaner metadataCleaner;
|
|
||||||
|
|
||||||
/** Cached list of JPEG segments we filter from the underlying stream */
|
/** Cached list of JPEG segments we filter from the underlying stream */
|
||||||
private List<Segment> segments;
|
private List<Segment> segments;
|
||||||
|
|
||||||
private int currentStreamIndex = 0;
|
private int currentStreamIndex = 0;
|
||||||
private List<Long> streamOffsets = new ArrayList<>();
|
private final List<Long> streamOffsets = new ArrayList<>();
|
||||||
|
|
||||||
protected JPEGImageReader(final ImageReaderSpi provider, final ImageReader delegate) {
|
protected JPEGImageReader(final ImageReaderSpi provider, final ImageReader delegate) {
|
||||||
super(provider);
|
super(provider);
|
||||||
@@ -161,8 +155,6 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
thumbnailReader.reset();
|
thumbnailReader.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
metadataCleaner = null;
|
|
||||||
|
|
||||||
installListeners();
|
installListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,19 +178,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
private boolean isLossless() throws IOException {
|
private boolean isLossless() throws IOException {
|
||||||
assertInput();
|
assertInput();
|
||||||
|
|
||||||
try {
|
return getSOF().marker == JPEG.SOF3;
|
||||||
if (getSOF().marker == JPEG.SOF3) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IIOException ignore) {
|
|
||||||
// May happen if no SOF is found, in case we'll just fall through
|
|
||||||
if (DEBUG) {
|
|
||||||
ignore.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -472,15 +452,12 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We'll need a read param
|
// We'll need a read param
|
||||||
Rectangle origSourceRegion;
|
|
||||||
if (param == null) {
|
if (param == null) {
|
||||||
param = delegate.getDefaultReadParam();
|
param = delegate.getDefaultReadParam();
|
||||||
origSourceRegion = null;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
origSourceRegion = param.getSourceRegion();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rectangle origSourceRegion = param.getSourceRegion();
|
||||||
|
|
||||||
Rectangle srcRegion = new Rectangle();
|
Rectangle srcRegion = new Rectangle();
|
||||||
Rectangle dstRegion = new Rectangle();
|
Rectangle dstRegion = new Rectangle();
|
||||||
computeRegions(param, origWidth, origHeight, image, srcRegion, dstRegion);
|
computeRegions(param, origWidth, origHeight, image, srcRegion, dstRegion);
|
||||||
@@ -534,7 +511,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
private JPEGColorSpace getSourceCSType(final JFIF jfif, final AdobeDCT adobeDCT, final Frame startOfFrame) throws IIOException {
|
static JPEGColorSpace getSourceCSType(final JFIF jfif, final AdobeDCT adobeDCT, final Frame startOfFrame) throws IIOException {
|
||||||
// Adapted from libjpeg jdapimin.c:
|
// Adapted from libjpeg jdapimin.c:
|
||||||
// Guess the input colorspace
|
// Guess the input colorspace
|
||||||
// (Wish JPEG committee had provided a real way to specify this...)
|
// (Wish JPEG committee had provided a real way to specify this...)
|
||||||
@@ -717,10 +694,11 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
private void initHeader(final int imageIndex) throws IOException {
|
private void initHeader(final int imageIndex) throws IOException {
|
||||||
if (imageIndex < 0) {
|
if (imageIndex < 0) {
|
||||||
throw new IllegalArgumentException("imageIndex < 0: " + imageIndex);
|
throw new IndexOutOfBoundsException("imageIndex < 0: " + imageIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (imageIndex == currentStreamIndex) {
|
if (imageIndex == currentStreamIndex) {
|
||||||
|
initHeader();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -743,26 +721,26 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
long lastKnownSOIOffset = streamOffsets.get(streamOffsets.size() - 1);
|
long lastKnownSOIOffset = streamOffsets.get(streamOffsets.size() - 1);
|
||||||
imageInput.seek(lastKnownSOIOffset);
|
imageInput.seek(lastKnownSOIOffset);
|
||||||
|
|
||||||
try (ImageInputStream stream = new BufferedImageInputStream(imageInput)) { // Extreme (10s -> 50ms) speedup if imageInput is FileIIS
|
try {
|
||||||
for (int i = streamOffsets.size() - 1; i < imageIndex; i++) {
|
for (int i = streamOffsets.size() - 1; i < imageIndex; i++) {
|
||||||
long start = 0;
|
long start = 0;
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
start = System.currentTimeMillis();
|
start = System.currentTimeMillis();
|
||||||
System.out.println(String.format("Start seeking for image index %d", i + 1));
|
System.out.printf("Start seeking for image index %d%n", i + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to skip over segments, as they may contain JPEG markers (eg. JFXX or EXIF thumbnail)
|
// Need to skip over segments, as they may contain JPEG markers (eg. JFXX or EXIF thumbnail)
|
||||||
JPEGSegmentUtil.readSegments(stream, Collections.<Integer, List<String>>emptyMap());
|
JPEGSegmentUtil.readSegments(imageInput, Collections.<Integer, List<String>>emptyMap());
|
||||||
|
|
||||||
// Now, search for EOI and following SOI...
|
// Now, search for EOI and following SOI...
|
||||||
int marker;
|
int marker;
|
||||||
while ((marker = stream.read()) != -1) {
|
while ((marker = imageInput.read()) != -1) {
|
||||||
if (marker == 0xFF && (0xFF00 | stream.readUnsignedByte()) == JPEG.EOI) {
|
if (marker == 0xFF && (0xFF00 | imageInput.readUnsignedByte()) == JPEG.EOI) {
|
||||||
// Found EOI, now the SOI should be nearby...
|
// Found EOI, now the SOI should be nearby...
|
||||||
while ((marker = stream.read()) != -1) {
|
while ((marker = imageInput.read()) != -1) {
|
||||||
if (marker == 0xFF && (0xFF00 | stream.readUnsignedByte()) == JPEG.SOI) {
|
if (marker == 0xFF && (0xFF00 | imageInput.readUnsignedByte()) == JPEG.SOI) {
|
||||||
long nextSOIOffset = stream.getStreamPosition() - 2;
|
long nextSOIOffset = imageInput.getStreamPosition() - 2;
|
||||||
imageInput.seek(nextSOIOffset);
|
imageInput.seek(nextSOIOffset);
|
||||||
streamOffsets.add(nextSOIOffset);
|
streamOffsets.add(nextSOIOffset);
|
||||||
|
|
||||||
@@ -776,10 +754,9 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
System.out.println(String.format("Seek in %d ms", System.currentTimeMillis() - start));
|
System.out.printf("Seek in %d ms%n", System.currentTimeMillis() - start);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (EOFException eof) {
|
catch (EOFException eof) {
|
||||||
IndexOutOfBoundsException ioobe = new IndexOutOfBoundsException("Image index " + imageIndex + " not found in stream");
|
IndexOutOfBoundsException ioobe = new IndexOutOfBoundsException("Image index " + imageIndex + " not found in stream");
|
||||||
@@ -837,11 +814,11 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
try {
|
try {
|
||||||
imageInput.seek(streamOffsets.get(currentStreamIndex));
|
imageInput.seek(streamOffsets.get(currentStreamIndex));
|
||||||
|
|
||||||
return JPEGSegmentUtil.readSegments(imageInput, SEGMENT_IDENTIFIERS);
|
return JPEGSegmentUtil.readSegments(imageInput, JPEGSegmentUtil.ALL_SEGMENTS);
|
||||||
}
|
}
|
||||||
catch (IIOException | IllegalArgumentException ignore) {
|
catch (IIOException | IllegalArgumentException e) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
ignore.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
@@ -905,16 +882,19 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
if (!exifSegments.isEmpty()) {
|
if (!exifSegments.isEmpty()) {
|
||||||
Application exif = exifSegments.get(0);
|
Application exif = exifSegments.get(0);
|
||||||
InputStream data = exif.data();
|
int offset = exif.identifier.length() + 2; // Incl. pad
|
||||||
|
|
||||||
if (data.read() == -1) { // Read pad
|
if (exif.data.length <= offset) {
|
||||||
processWarningOccurred("Exif chunk has no data.");
|
processWarningOccurred("Exif chunk has no data.");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ImageInputStream stream = new MemoryCacheImageInputStream(data);
|
// TODO: Consider returning ByteArrayImageInputStream from Segment.data()
|
||||||
return (CompoundDirectory) new TIFFReader().read(stream);
|
try (ImageInputStream stream = new ByteArrayImageInputStream(exif.data, offset, exif.data.length - offset)) {
|
||||||
|
return (CompoundDirectory) new TIFFReader().read(stream);
|
||||||
// TODO: Directory offset of thumbnail is wrong/relative to container stream, causing trouble for the TIFFReader...
|
}
|
||||||
|
catch (IIOException e) {
|
||||||
|
processWarningOccurred("Exif chunk is present, but can't be read: " + e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1102,6 +1082,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
// Read JFIF thumbnails if present
|
// Read JFIF thumbnails if present
|
||||||
JFIF jfif = getJFIF();
|
JFIF jfif = getJFIF();
|
||||||
if (jfif != null && jfif.thumbnail != null) {
|
if (jfif != null && jfif.thumbnail != null) {
|
||||||
|
// TODO: Check if the JFIF segment really has room for this thumbnail?
|
||||||
thumbnails.add(new JFIFThumbnailReader(thumbnailProgressDelegator, imageIndex, thumbnails.size(), jfif));
|
thumbnails.add(new JFIFThumbnailReader(thumbnailProgressDelegator, imageIndex, thumbnails.size(), jfif));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1112,6 +1093,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
case JFXX.JPEG:
|
case JFXX.JPEG:
|
||||||
case JFXX.INDEXED:
|
case JFXX.INDEXED:
|
||||||
case JFXX.RGB:
|
case JFXX.RGB:
|
||||||
|
// TODO: Check if the JFXX segment really has room for this thumbnail?
|
||||||
thumbnails.add(new JFXXThumbnailReader(thumbnailProgressDelegator, getThumbnailReader(), imageIndex, thumbnails.size(), jfxx));
|
thumbnails.add(new JFXXThumbnailReader(thumbnailProgressDelegator, getThumbnailReader(), imageIndex, thumbnails.size(), jfxx));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -1125,48 +1107,77 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
Application exif = exifSegments.get(0);
|
Application exif = exifSegments.get(0);
|
||||||
|
|
||||||
// Identifier is "Exif\0" + 1 byte pad
|
// Identifier is "Exif\0" + 1 byte pad
|
||||||
int offset = exif.identifier.length() + 2;
|
int dataOffset = exif.identifier.length() + 2;
|
||||||
|
|
||||||
if (exif.data.length <= offset) {
|
if (exif.data.length <= dataOffset) {
|
||||||
processWarningOccurred("Exif chunk has no data.");
|
processWarningOccurred("Exif chunk has no data.");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ImageInputStream stream = new ByteArrayImageInputStream(exif.data, offset, exif.data.length - offset);
|
ImageInputStream stream = new ByteArrayImageInputStream(exif.data, dataOffset, exif.data.length - dataOffset);
|
||||||
CompoundDirectory exifMetadata = (CompoundDirectory) new TIFFReader().read(stream);
|
try {
|
||||||
|
CompoundDirectory exifMetadata = (CompoundDirectory) new TIFFReader().read(stream);
|
||||||
|
|
||||||
if (exifMetadata.directoryCount() == 2) {
|
if (exifMetadata.directoryCount() == 2) {
|
||||||
Directory ifd1 = exifMetadata.getDirectory(1);
|
Directory ifd1 = exifMetadata.getDirectory(1);
|
||||||
|
|
||||||
// Compression: 1 = no compression, 6 = JPEG compression (default)
|
// Compression: 1 = no compression, 6 = JPEG compression (default)
|
||||||
Entry compressionEntry = ifd1.getEntryById(TIFF.TAG_COMPRESSION);
|
Entry compressionEntry = ifd1.getEntryById(TIFF.TAG_COMPRESSION);
|
||||||
int compression = compressionEntry == null ? 6 : ((Number) compressionEntry.getValue()).intValue();
|
int compression = compressionEntry == null ? 6 : ((Number) compressionEntry.getValue()).intValue();
|
||||||
|
|
||||||
if (compression == 6) {
|
if (compression == 6) {
|
||||||
if (ifd1.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT) != null) {
|
Entry jpegOffEntry = ifd1.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT);
|
||||||
Entry jpegLength = ifd1.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
|
if (jpegOffEntry != null) {
|
||||||
|
Entry jpegLenEntry = ifd1.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
|
||||||
|
|
||||||
if ((jpegLength == null || ((Number) jpegLength.getValue()).longValue() > 0)) {
|
// Test if Exif thumbnail is contained within the Exif segment (offset + length <= segment.length)
|
||||||
thumbnails.add(new EXIFThumbnailReader(thumbnailProgressDelegator, getThumbnailReader(), 0, thumbnails.size(), ifd1, stream));
|
long jpegOffset = ((Number) jpegOffEntry.getValue()).longValue();
|
||||||
|
long jpegLength = jpegLenEntry != null ? ((Number) jpegLenEntry.getValue()).longValue() : -1;
|
||||||
|
if (jpegLength > 0 && jpegOffset + jpegLength <= stream.length()) {
|
||||||
|
// Verify first bytes are FFD8
|
||||||
|
stream.seek(jpegOffset);
|
||||||
|
stream.setByteOrder(ByteOrder.BIG_ENDIAN);
|
||||||
|
if (stream.readUnsignedShort() == JPEG.SOI) {
|
||||||
|
thumbnails.add(new EXIFThumbnailReader(thumbnailProgressDelegator, getThumbnailReader(), 0, thumbnails.size(), ifd1, stream));
|
||||||
|
}
|
||||||
|
// TODO: Simplify this warning fallback stuff...
|
||||||
|
else {
|
||||||
|
processWarningOccurred("EXIF IFD with empty or incomplete JPEG thumbnail");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
processWarningOccurred("EXIF IFD with empty or incomplete JPEG thumbnail");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
processWarningOccurred("EXIF IFD with empty (zero-length) thumbnail");
|
processWarningOccurred("EXIF IFD with JPEG thumbnail missing JPEGInterchangeFormat tag");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (compression == 1) {
|
||||||
|
Entry stripOffEntry = ifd1.getEntryById(TIFF.TAG_STRIP_OFFSETS);
|
||||||
|
if (stripOffEntry != null) {
|
||||||
|
long stripOffset = ((Number) stripOffEntry.getValue()).longValue();
|
||||||
|
|
||||||
|
if (stripOffset < stream.length()) {
|
||||||
|
// TODO: Verify length of Exif thumbnail vs length of segment like in JPEG
|
||||||
|
// ...but this requires so many extra values... Instead move this logic to the
|
||||||
|
// EXIFThumbnailReader?
|
||||||
|
thumbnails.add(new EXIFThumbnailReader(thumbnailProgressDelegator, getThumbnailReader(), 0, thumbnails.size(), ifd1, stream));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
processWarningOccurred("EXIF IFD with empty or incomplete uncompressed thumbnail");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
processWarningOccurred("EXIF IFD with uncompressed thumbnail missing StripOffsets tag");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
processWarningOccurred("EXIF IFD with JPEG thumbnail missing JPEGInterchangeFormat tag");
|
processWarningOccurred("EXIF IFD with unknown compression (expected 1 or 6): " + compression);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (compression == 1) {
|
}
|
||||||
if (ifd1.getEntryById(TIFF.TAG_STRIP_OFFSETS) != null) {
|
catch (IIOException e) {
|
||||||
thumbnails.add(new EXIFThumbnailReader(thumbnailProgressDelegator, getThumbnailReader(), 0, thumbnails.size(), ifd1, stream));
|
processWarningOccurred("Exif chunk present, but can't be read: " + e.getMessage());
|
||||||
}
|
|
||||||
else {
|
|
||||||
processWarningOccurred("EXIF IFD with uncompressed thumbnail missing StripOffsets tag");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
processWarningOccurred("EXIF IFD with unknown compression (expected 1 or 6): " + compression);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1211,45 +1222,24 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
public BufferedImage readThumbnail(int imageIndex, int thumbnailIndex) throws IOException {
|
public BufferedImage readThumbnail(int imageIndex, int thumbnailIndex) throws IOException {
|
||||||
checkThumbnailBounds(imageIndex, thumbnailIndex);
|
checkThumbnailBounds(imageIndex, thumbnailIndex);
|
||||||
|
|
||||||
return thumbnails.get(thumbnailIndex).read();
|
// processThumbnailStarted(imageIndex, thumbnailIndex);
|
||||||
|
// processThumbnailProgress(0f);
|
||||||
|
|
||||||
|
BufferedImage thumbnail = thumbnails.get(thumbnailIndex).read();;
|
||||||
|
|
||||||
|
// processThumbnailProgress(100f);
|
||||||
|
// processThumbnailComplete();
|
||||||
|
|
||||||
|
return thumbnail;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Metadata
|
// Metadata
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IIOMetadata getImageMetadata(int imageIndex) throws IOException {
|
public IIOMetadata getImageMetadata(int imageIndex) throws IOException {
|
||||||
// checkBounds needed, as we catch the IndexOutOfBoundsException below.
|
|
||||||
checkBounds(imageIndex);
|
|
||||||
initHeader(imageIndex);
|
initHeader(imageIndex);
|
||||||
|
|
||||||
IIOMetadata imageMetadata;
|
return new JPEGImage10Metadata(segments, getSOF(), getJFIF(), getJFXX(), getEmbeddedICCProfile(true), getAdobeDCT(), getExif());
|
||||||
|
|
||||||
if (isLossless()) {
|
|
||||||
return new JPEGImage10Metadata(segments);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
try {
|
|
||||||
imageMetadata = delegate.getImageMetadata(0);
|
|
||||||
}
|
|
||||||
catch (IndexOutOfBoundsException knownIssue) {
|
|
||||||
// TMI-101: com.sun.imageio.plugins.jpeg.JPEGBuffer doesn't do proper sanity check of input data.
|
|
||||||
throw new IIOException("Corrupt JPEG data: Bad segment length", knownIssue);
|
|
||||||
}
|
|
||||||
catch (NegativeArraySizeException knownIssue) {
|
|
||||||
// Most likely from com.sun.imageio.plugins.jpeg.SOSMarkerSegment
|
|
||||||
throw new IIOException("Corrupt JPEG data: Bad component count", knownIssue);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (imageMetadata != null && Arrays.asList(imageMetadata.getMetadataFormatNames()).contains(JPEGImage10MetadataCleaner.JAVAX_IMAGEIO_JPEG_IMAGE_1_0)) {
|
|
||||||
if (metadataCleaner == null) {
|
|
||||||
metadataCleaner = new JPEGImage10MetadataCleaner(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
return metadataCleaner.cleanMetadata(imageMetadata);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return imageMetadata;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1417,7 +1407,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
final String arg = args[argIdx];
|
final String arg = args[argIdx];
|
||||||
|
|
||||||
if (arg.charAt(0) == '-') {
|
if (arg.charAt(0) == '-') {
|
||||||
if (arg.equals("-s") || arg.equals("--subsample") && args.length > argIdx) {
|
if (arg.equals("-s") || arg.equals("--subsample") && args.length > argIdx + 1) {
|
||||||
String[] sub = args[++argIdx].split(",");
|
String[] sub = args[++argIdx].split(",");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -1436,7 +1426,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
|||||||
System.err.println("Bad sub sampling (x,y): '" + args[argIdx] + "'");
|
System.err.println("Bad sub sampling (x,y): '" + args[argIdx] + "'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (arg.equals("-r") || arg.equals("--roi") && args.length > argIdx) {
|
else if (arg.equals("-r") || arg.equals("--roi") && args.length > argIdx + 1) {
|
||||||
String[] region = args[++argIdx].split(",");
|
String[] region = args[++argIdx].split(",");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ import java.nio.charset.StandardCharsets;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import static com.twelvemonkeys.imageio.plugins.jpeg.JPEGImage10MetadataCleaner.JAVAX_IMAGEIO_JPEG_IMAGE_1_0;
|
import static com.twelvemonkeys.imageio.plugins.jpeg.JPEGImage10Metadata.JAVAX_IMAGEIO_JPEG_IMAGE_1_0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JPEGImageWriter
|
* JPEGImageWriter
|
||||||
@@ -159,6 +159,17 @@ public final class JPEGImageWriter extends ImageWriterBase {
|
|||||||
writeCMYK(streamMetadata, image, param);
|
writeCMYK(streamMetadata, image, param);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// If the image metadata is our substitute, convert it back to native com.sun format
|
||||||
|
if (image.getMetadata() instanceof JPEGImage10Metadata) {
|
||||||
|
ImageTypeSpecifier type = image.hasRaster() ? null : ImageTypeSpecifier.createFromRenderedImage(image.getRenderedImage());
|
||||||
|
IIOMetadata nativeMetadata = delegate.getDefaultImageMetadata(type, param);
|
||||||
|
|
||||||
|
JPEGImage10Metadata metadata = (JPEGImage10Metadata) image.getMetadata();
|
||||||
|
nativeMetadata.setFromTree(metadata.getNativeMetadataFormatName(), metadata.getNativeTree());
|
||||||
|
|
||||||
|
image.setMetadata(nativeMetadata);
|
||||||
|
}
|
||||||
|
|
||||||
delegate.write(streamMetadata, image, param);
|
delegate.write(streamMetadata, image, param);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import javax.imageio.IIOException;
|
|||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
final class JPEGLosslessDecoder {
|
final class JPEGLosslessDecoder {
|
||||||
@@ -51,12 +52,12 @@ final class JPEGLosslessDecoder {
|
|||||||
private final QuantizationTable quantTable;
|
private final QuantizationTable quantTable;
|
||||||
private Scan scan;
|
private Scan scan;
|
||||||
|
|
||||||
private final int HuffTab[][][] = new int[4][2][MAX_HUFFMAN_SUBTREE * 256];
|
private final int[][][] HuffTab = new int[4][2][MAX_HUFFMAN_SUBTREE * 256];
|
||||||
private final int IDCT_Source[] = new int[64];
|
private final int[] IDCT_Source = new int[64];
|
||||||
private final int nBlock[] = new int[10]; // number of blocks in the i-th Comp in a scan
|
private final int[] nBlock = new int[10]; // number of blocks in the i-th Comp in a scan
|
||||||
private final int[] acTab[] = new int[10][]; // ac HuffTab for the i-th Comp in a scan
|
private final int[][] acTab = new int[10][]; // ac HuffTab for the i-th Comp in a scan
|
||||||
private final int[] dcTab[] = new int[10][]; // dc HuffTab for the i-th Comp in a scan
|
private final int[][] dcTab = new int[10][]; // dc HuffTab for the i-th Comp in a scan
|
||||||
private final int[] qTab[] = new int[10][]; // quantization table for the i-th Comp in a scan
|
private final int[][] qTab = new int[10][]; // quantization table for the i-th Comp in a scan
|
||||||
|
|
||||||
private boolean restarting;
|
private boolean restarting;
|
||||||
private int marker;
|
private int marker;
|
||||||
@@ -70,7 +71,7 @@ final class JPEGLosslessDecoder {
|
|||||||
private int mask;
|
private int mask;
|
||||||
private int[][] outputData;
|
private int[][] outputData;
|
||||||
|
|
||||||
private static final int IDCT_P[] = {
|
private static final int[] IDCT_P = {
|
||||||
0, 5, 40, 16, 45, 2, 7, 42,
|
0, 5, 40, 16, 45, 2, 7, 42,
|
||||||
21, 56, 8, 61, 18, 47, 1, 4,
|
21, 56, 8, 61, 18, 47, 1, 4,
|
||||||
41, 23, 58, 13, 32, 24, 37, 10,
|
41, 23, 58, 13, 32, 24, 37, 10,
|
||||||
@@ -80,16 +81,6 @@ final class JPEGLosslessDecoder {
|
|||||||
50, 55, 25, 36, 11, 62, 14, 35,
|
50, 55, 25, 36, 11, 62, 14, 35,
|
||||||
28, 49, 52, 27, 38, 30, 51, 54
|
28, 49, 52, 27, 38, 30, 51, 54
|
||||||
};
|
};
|
||||||
private static final int TABLE[] = {
|
|
||||||
0, 1, 5, 6, 14, 15, 27, 28,
|
|
||||||
2, 4, 7, 13, 16, 26, 29, 42,
|
|
||||||
3, 8, 12, 17, 25, 30, 41, 43,
|
|
||||||
9, 11, 18, 24, 31, 40, 44, 53,
|
|
||||||
10, 19, 23, 32, 39, 45, 52, 54,
|
|
||||||
20, 22, 33, 38, 46, 51, 55, 60,
|
|
||||||
21, 34, 37, 47, 50, 56, 59, 61,
|
|
||||||
35, 36, 48, 49, 57, 58, 62, 63
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final int RESTART_MARKER_BEGIN = 0xFFD0;
|
private static final int RESTART_MARKER_BEGIN = 0xFFD0;
|
||||||
private static final int RESTART_MARKER_END = 0xFFD7;
|
private static final int RESTART_MARKER_END = 0xFFD7;
|
||||||
@@ -158,7 +149,7 @@ final class JPEGLosslessDecoder {
|
|||||||
huffTable.buildHuffTables(HuffTab);
|
huffTable.buildHuffTables(HuffTab);
|
||||||
}
|
}
|
||||||
|
|
||||||
quantTable.enhanceTables(TABLE);
|
quantTable.enhanceTables();
|
||||||
|
|
||||||
current = input.readUnsignedShort();
|
current = input.readUnsignedShort();
|
||||||
|
|
||||||
@@ -185,11 +176,10 @@ final class JPEGLosslessDecoder {
|
|||||||
selection = scan.spectralSelStart;
|
selection = scan.spectralSelStart;
|
||||||
|
|
||||||
final Scan.Component[] scanComps = scan.components;
|
final Scan.Component[] scanComps = scan.components;
|
||||||
final int[][] quantTables = quantTable.quantTables;
|
|
||||||
|
|
||||||
for (int i = 0; i < numComp; i++) {
|
for (int i = 0; i < numComp; i++) {
|
||||||
Frame.Component component = getComponentSpec(components, scanComps[i].scanCompSel);
|
Frame.Component component = getComponentSpec(components, scanComps[i].scanCompSel);
|
||||||
qTab[i] = quantTables[component.qtSel];
|
qTab[i] = quantTable.qTable(component.qtSel);
|
||||||
nBlock[i] = component.vSub * component.hSub;
|
nBlock[i] = component.vSub * component.hSub;
|
||||||
|
|
||||||
int dcTabSel = scanComps[i].dcTabSel;
|
int dcTabSel = scanComps[i].dcTabSel;
|
||||||
@@ -220,18 +210,18 @@ final class JPEGLosslessDecoder {
|
|||||||
outputData[componentIndex] = new int[xDim * yDim];
|
outputData[componentIndex] = new int[xDim * yDim];
|
||||||
}
|
}
|
||||||
|
|
||||||
final int firstValue[] = new int[numComp];
|
final int[] firstValue = new int[numComp];
|
||||||
for (int i = 0; i < numComp; i++) {
|
for (int i = 0; i < numComp; i++) {
|
||||||
firstValue[i] = (1 << (precision - 1));
|
firstValue[i] = (1 << (precision - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
final int pred[] = new int[numComp];
|
final int[] pred = new int[numComp];
|
||||||
|
|
||||||
scanNum++;
|
scanNum++;
|
||||||
|
|
||||||
while (true) { // Decode one scan
|
while (true) { // Decode one scan
|
||||||
int temp[] = new int[1]; // to store remainder bits
|
int[] temp = new int[1]; // to store remainder bits
|
||||||
int index[] = new int[1];
|
int[] index = new int[1];
|
||||||
|
|
||||||
System.arraycopy(firstValue, 0, pred, 0, numComp);
|
System.arraycopy(firstValue, 0, pred, 0, numComp);
|
||||||
|
|
||||||
@@ -288,7 +278,7 @@ final class JPEGLosslessDecoder {
|
|||||||
private boolean useACForDC(final int dcTabSel) {
|
private boolean useACForDC(final int dcTabSel) {
|
||||||
if (isLossless()) {
|
if (isLossless()) {
|
||||||
for (HuffmanTable huffTable : huffTables) {
|
for (HuffmanTable huffTable : huffTables) {
|
||||||
if (huffTable.tc[dcTabSel][0] == 0 && huffTable.tc[dcTabSel][1] != 0) {
|
if (!huffTable.isPresent(dcTabSel, 0) && huffTable.isPresent(dcTabSel, 1)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -324,7 +314,7 @@ final class JPEGLosslessDecoder {
|
|||||||
return Scan.read(input, length);
|
return Scan.read(input, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int decode(final int prev[], final int temp[], final int index[]) throws IOException {
|
private int decode(final int[] prev, final int[] temp, final int[] index) throws IOException {
|
||||||
if (numComp == 1) {
|
if (numComp == 1) {
|
||||||
return decodeSingle(prev, temp, index);
|
return decodeSingle(prev, temp, index);
|
||||||
}
|
}
|
||||||
@@ -336,7 +326,7 @@ final class JPEGLosslessDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int decodeSingle(final int prev[], final int temp[], final int index[]) throws IOException {
|
private int decodeSingle(final int[] prev, final int[] temp, final int[] index) throws IOException {
|
||||||
// At the beginning of the first line and
|
// At the beginning of the first line and
|
||||||
// at the beginning of each restart interval the prediction value of 2P – 1 is used, where P is the input precision.
|
// at the beginning of each restart interval the prediction value of 2P – 1 is used, where P is the input precision.
|
||||||
if (restarting) {
|
if (restarting) {
|
||||||
@@ -390,7 +380,7 @@ final class JPEGLosslessDecoder {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int decodeRGB(final int prev[], final int temp[], final int index[]) throws IOException {
|
private int decodeRGB(final int[] prev, final int[] temp, final int[] index) throws IOException {
|
||||||
final int[] outputRedData = outputData[0];
|
final int[] outputRedData = outputData[0];
|
||||||
final int[] outputGreenData = outputData[1];
|
final int[] outputGreenData = outputData[1];
|
||||||
final int[] outputBlueData = outputData[2];
|
final int[] outputBlueData = outputData[2];
|
||||||
@@ -435,7 +425,7 @@ final class JPEGLosslessDecoder {
|
|||||||
return decode0(prev, temp, index);
|
return decode0(prev, temp, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int decodeAny(final int prev[], final int temp[], final int index[]) throws IOException {
|
private int decodeAny(final int[] prev, final int[] temp, final int[] index) throws IOException {
|
||||||
for (int componentIndex = 0; componentIndex < outputData.length; ++componentIndex) {
|
for (int componentIndex = 0; componentIndex < outputData.length; ++componentIndex) {
|
||||||
final int[] outputData = this.outputData[componentIndex];
|
final int[] outputData = this.outputData[componentIndex];
|
||||||
final int previous;
|
final int previous;
|
||||||
@@ -469,17 +459,17 @@ final class JPEGLosslessDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int decode0(int[] prev, int[] temp, int[] index) throws IOException {
|
private int decode0(int[] prev, int[] temp, int[] index) throws IOException {
|
||||||
int value, actab[], dctab[];
|
int value;
|
||||||
int qtab[];
|
int[] actab;
|
||||||
|
int[] dctab;
|
||||||
|
int[] qtab;
|
||||||
|
|
||||||
for (int ctrC = 0; ctrC < numComp; ctrC++) {
|
for (int ctrC = 0; ctrC < numComp; ctrC++) {
|
||||||
qtab = qTab[ctrC];
|
qtab = qTab[ctrC];
|
||||||
actab = acTab[ctrC];
|
actab = acTab[ctrC];
|
||||||
dctab = dcTab[ctrC];
|
dctab = dcTab[ctrC];
|
||||||
for (int i = 0; i < nBlock[ctrC]; i++) {
|
for (int i = 0; i < nBlock[ctrC]; i++) {
|
||||||
for (int k = 0; k < IDCT_Source.length; k++) {
|
Arrays.fill(IDCT_Source, 0);
|
||||||
IDCT_Source[k] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = getHuffmanValue(dctab, temp, index);
|
value = getHuffmanValue(dctab, temp, index);
|
||||||
|
|
||||||
@@ -545,7 +535,7 @@ final class JPEGLosslessDecoder {
|
|||||||
// and marker_index=9
|
// and marker_index=9
|
||||||
// If marker_index=9 then index is always > 8, or HuffmanValue()
|
// If marker_index=9 then index is always > 8, or HuffmanValue()
|
||||||
// will not be called
|
// will not be called
|
||||||
private int getHuffmanValue(final int table[], final int temp[], final int index[]) throws IOException {
|
private int getHuffmanValue(final int[] table, final int[] temp, final int[] index) throws IOException {
|
||||||
int code, input;
|
int code, input;
|
||||||
final int mask = 0xFFFF;
|
final int mask = 0xFFFF;
|
||||||
|
|
||||||
@@ -603,7 +593,7 @@ final class JPEGLosslessDecoder {
|
|||||||
return code & 0xFF;
|
return code & 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getn(final int[] pred, final int n, final int temp[], final int index[]) throws IOException {
|
private int getn(final int[] pred, final int n, final int[] temp, final int[] index) throws IOException {
|
||||||
int result;
|
int result;
|
||||||
final int one = 1;
|
final int one = 1;
|
||||||
final int n_one = -1;
|
final int n_one = -1;
|
||||||
@@ -688,7 +678,7 @@ final class JPEGLosslessDecoder {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getPreviousX(final int data[]) {
|
private int getPreviousX(final int[] data) {
|
||||||
if (xLoc > 0) {
|
if (xLoc > 0) {
|
||||||
return data[((yLoc * xDim) + xLoc) - 1];
|
return data[((yLoc * xDim) + xLoc) - 1];
|
||||||
}
|
}
|
||||||
@@ -700,7 +690,7 @@ final class JPEGLosslessDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getPreviousXY(final int data[]) {
|
private int getPreviousXY(final int[] data) {
|
||||||
if ((xLoc > 0) && (yLoc > 0)) {
|
if ((xLoc > 0) && (yLoc > 0)) {
|
||||||
return data[(((yLoc - 1) * xDim) + xLoc) - 1];
|
return data[(((yLoc - 1) * xDim) + xLoc) - 1];
|
||||||
}
|
}
|
||||||
@@ -709,7 +699,7 @@ final class JPEGLosslessDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getPreviousY(final int data[]) {
|
private int getPreviousY(final int[] data) {
|
||||||
if (yLoc > 0) {
|
if (yLoc > 0) {
|
||||||
return data[((yLoc - 1) * xDim) + xLoc];
|
return data[((yLoc - 1) * xDim) + xLoc];
|
||||||
}
|
}
|
||||||
@@ -722,7 +712,7 @@ final class JPEGLosslessDecoder {
|
|||||||
return (xLoc == (xDim - 1)) && (yLoc == (yDim - 1));
|
return (xLoc == (xDim - 1)) && (yLoc == (yDim - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void output(final int pred[]) {
|
private void output(final int[] pred) {
|
||||||
if (numComp == 1) {
|
if (numComp == 1) {
|
||||||
outputSingle(pred);
|
outputSingle(pred);
|
||||||
}
|
}
|
||||||
@@ -734,7 +724,7 @@ final class JPEGLosslessDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void outputSingle(final int pred[]) {
|
private void outputSingle(final int[] pred) {
|
||||||
if ((xLoc < xDim) && (yLoc < yDim)) {
|
if ((xLoc < xDim) && (yLoc < yDim)) {
|
||||||
outputData[0][(yLoc * xDim) + xLoc] = mask & pred[0];
|
outputData[0][(yLoc * xDim) + xLoc] = mask & pred[0];
|
||||||
xLoc++;
|
xLoc++;
|
||||||
@@ -746,7 +736,7 @@ final class JPEGLosslessDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void outputRGB(final int pred[]) {
|
private void outputRGB(final int[] pred) {
|
||||||
if ((xLoc < xDim) && (yLoc < yDim)) {
|
if ((xLoc < xDim) && (yLoc < yDim)) {
|
||||||
final int index = (yLoc * xDim) + xLoc;
|
final int index = (yLoc * xDim) + xLoc;
|
||||||
outputData[0][index] = pred[0];
|
outputData[0][index] = pred[0];
|
||||||
@@ -761,7 +751,7 @@ final class JPEGLosslessDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void outputAny(final int pred[]) {
|
private void outputAny(final int[] pred) {
|
||||||
if ((xLoc < xDim) && (yLoc < yDim)) {
|
if ((xLoc < xDim) && (yLoc < yDim)) {
|
||||||
final int index = (yLoc * xDim) + xLoc;
|
final int index = (yLoc * xDim) + xLoc;
|
||||||
for (int componentIndex = 0; componentIndex < outputData.length; ++componentIndex) {
|
for (int componentIndex = 0; componentIndex < outputData.length; ++componentIndex) {
|
||||||
|
|||||||
@@ -572,12 +572,17 @@ final class JPEGSegmentImageInputStream extends ImageInputStreamImpl {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int read(final ImageInputStream stream) {
|
public int read(final ImageInputStream stream) {
|
||||||
return data[pos++] & 0xff;
|
return data.length > pos ? data[pos++] & 0xff : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int read(final ImageInputStream stream, byte[] b, int off, int len) {
|
public int read(final ImageInputStream stream, byte[] b, int off, int len) {
|
||||||
int length = Math.min(data.length - pos, len);
|
int dataLeft = data.length - pos;
|
||||||
|
if (dataLeft <= 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int length = Math.min(dataLeft, len);
|
||||||
System.arraycopy(data, pos, b, off, length);
|
System.arraycopy(data, pos, b, off, length);
|
||||||
pos += length;
|
pos += length;
|
||||||
|
|
||||||
|
|||||||
@@ -35,35 +35,42 @@ package com.twelvemonkeys.imageio.plugins.jpeg;
|
|||||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
import javax.imageio.IIOException;
|
||||||
|
import javax.imageio.plugins.jpeg.JPEGQTable;
|
||||||
import java.io.DataInput;
|
import java.io.DataInput;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
final class QuantizationTable extends Segment {
|
final class QuantizationTable extends Segment {
|
||||||
|
|
||||||
private final int precision[] = new int[4]; // Quantization precision 8 or 16
|
private static final int[] ZIGZAG = {
|
||||||
private final int[] tq = new int[4]; // 1: this table is presented
|
0, 1, 5, 6, 14, 15, 27, 28,
|
||||||
|
2, 4, 7, 13, 16, 26, 29, 42,
|
||||||
|
3, 8, 12, 17, 25, 30, 41, 43,
|
||||||
|
9, 11, 18, 24, 31, 40, 44, 53,
|
||||||
|
10, 19, 23, 32, 39, 45, 52, 54,
|
||||||
|
20, 22, 33, 38, 46, 51, 55, 60,
|
||||||
|
21, 34, 37, 47, 50, 56, 59, 61,
|
||||||
|
35, 36, 48, 49, 57, 58, 62, 63
|
||||||
|
};
|
||||||
|
|
||||||
final int quantTables[][] = new int[4][64]; // Tables
|
private final int[] precision = new int[4]; // Quantization precision 8 or 16
|
||||||
|
private final boolean[] tq = new boolean[4]; // 1: this table is present
|
||||||
|
|
||||||
|
private final int[][] quantTables = new int[4][64]; // Tables
|
||||||
|
|
||||||
QuantizationTable() {
|
QuantizationTable() {
|
||||||
super(JPEG.DQT);
|
super(JPEG.DQT);
|
||||||
|
|
||||||
tq[0] = 0;
|
|
||||||
tq[1] = 0;
|
|
||||||
tq[2] = 0;
|
|
||||||
tq[3] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Get rid of table param, make it a member?
|
// TODO: Consider creating a copy for the decoder here, as we need to keep the original values for the metadata
|
||||||
void enhanceTables(final int[] table) throws IOException {
|
void enhanceTables() {
|
||||||
for (int t = 0; t < 4; t++) {
|
for (int t = 0; t < 4; t++) {
|
||||||
if (tq[t] != 0) {
|
if (tq[t]) {
|
||||||
enhanceQuantizationTable(quantTables[t], table);
|
enhanceQuantizationTable(quantTables[t], ZIGZAG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void enhanceQuantizationTable(final int qtab[], final int[] table) {
|
private void enhanceQuantizationTable(final int[] qtab, final int[] table) {
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
qtab[table[ i]] *= 90;
|
qtab[table[ i]] *= 90;
|
||||||
qtab[table[(4 * 8) + i]] *= 90;
|
qtab[table[(4 * 8) + i]] *= 90;
|
||||||
@@ -122,7 +129,7 @@ final class QuantizationTable extends Segment {
|
|||||||
throw new IIOException("Unexpected JPEG Quantization Table precision: " + table.precision[t]);
|
throw new IIOException("Unexpected JPEG Quantization Table precision: " + table.precision[t]);
|
||||||
}
|
}
|
||||||
|
|
||||||
table.tq[t] = 1;
|
table.tq[t] = true;
|
||||||
|
|
||||||
if (table.precision[t] == 8) {
|
if (table.precision[t] == 8) {
|
||||||
for (int i = 0; i < 64; i++) {
|
for (int i = 0; i < 64; i++) {
|
||||||
@@ -152,4 +159,28 @@ final class QuantizationTable extends Segment {
|
|||||||
|
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isPresent(int tabelId) {
|
||||||
|
return tq[tabelId];
|
||||||
|
}
|
||||||
|
|
||||||
|
int precision(int tableId) {
|
||||||
|
return precision[tableId];
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] qTable(int tabelId) {
|
||||||
|
return quantTables[tabelId];
|
||||||
|
}
|
||||||
|
|
||||||
|
JPEGQTable toNativeTable(int tableId) {
|
||||||
|
// TODO: Should de-zigzag (ie. "natural order") while reading
|
||||||
|
// TODO: ...and make sure the table isn't "enhanced"...
|
||||||
|
int[] qTable = new int[quantTables[tableId].length];
|
||||||
|
|
||||||
|
for (int i = 0; i < qTable.length; i++) {
|
||||||
|
qTable[i] = quantTables[tableId][ZIGZAG[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
return new JPEGQTable(qTable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,12 +85,12 @@ public class JPEGImage10MetadataCleanerTest {
|
|||||||
reader.setInput(input);
|
reader.setInput(input);
|
||||||
|
|
||||||
IIOMetadata original = origReader.getImageMetadata(0);
|
IIOMetadata original = origReader.getImageMetadata(0);
|
||||||
IIOMetadataNode origTree = (IIOMetadataNode) original.getAsTree(JPEGImage10MetadataCleaner.JAVAX_IMAGEIO_JPEG_IMAGE_1_0);
|
IIOMetadataNode origTree = (IIOMetadataNode) original.getAsTree(JPEGImage10Metadata.JAVAX_IMAGEIO_JPEG_IMAGE_1_0);
|
||||||
|
|
||||||
JPEGImage10MetadataCleaner cleaner = new JPEGImage10MetadataCleaner((JPEGImageReader) reader);
|
JPEGImage10MetadataCleaner cleaner = new JPEGImage10MetadataCleaner((JPEGImageReader) reader);
|
||||||
IIOMetadata cleaned = cleaner.cleanMetadata(origReader.getImageMetadata(0));
|
IIOMetadata cleaned = cleaner.cleanMetadata(origReader.getImageMetadata(0));
|
||||||
|
|
||||||
IIOMetadataNode cleanTree = (IIOMetadataNode) cleaned.getAsTree(JPEGImage10MetadataCleaner.JAVAX_IMAGEIO_JPEG_IMAGE_1_0);
|
IIOMetadataNode cleanTree = (IIOMetadataNode) cleaned.getAsTree(JPEGImage10Metadata.JAVAX_IMAGEIO_JPEG_IMAGE_1_0);
|
||||||
|
|
||||||
NodeList origDHT = origTree.getElementsByTagName("dht");
|
NodeList origDHT = origTree.getElementsByTagName("dht");
|
||||||
assertEquals(1, origDHT.getLength());
|
assertEquals(1, origDHT.getLength());
|
||||||
|
|||||||
@@ -31,8 +31,9 @@
|
|||||||
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.lang.StringUtil;
|
||||||
|
|
||||||
import org.hamcrest.core.IsInstanceOf;
|
import org.hamcrest.core.IsInstanceOf;
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.internal.matchers.GreaterThan;
|
import org.mockito.internal.matchers.GreaterThan;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
@@ -60,6 +61,9 @@ import java.util.List;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static com.twelvemonkeys.imageio.util.IIOUtil.lookupProviderByName;
|
import static com.twelvemonkeys.imageio.util.IIOUtil.lookupProviderByName;
|
||||||
|
import static org.hamcrest.CoreMatchers.allOf;
|
||||||
|
import static org.hamcrest.CoreMatchers.containsString;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assume.assumeNoException;
|
import static org.junit.Assume.assumeNoException;
|
||||||
import static org.junit.Assume.assumeNotNull;
|
import static org.junit.Assume.assumeNotNull;
|
||||||
@@ -77,7 +81,10 @@ import static org.mockito.Mockito.*;
|
|||||||
*/
|
*/
|
||||||
public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader> {
|
public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader> {
|
||||||
|
|
||||||
private static final JPEGImageReaderSpi SPI = new JPEGImageReaderSpi(lookupDelegateProvider());
|
@Override
|
||||||
|
protected ImageReaderSpi createProvider() {
|
||||||
|
return new JPEGImageReaderSpi(lookupDelegateProvider());
|
||||||
|
}
|
||||||
|
|
||||||
private static ImageReaderSpi lookupDelegateProvider() {
|
private static ImageReaderSpi lookupDelegateProvider() {
|
||||||
return lookupProviderByName(IIORegistry.getDefaultInstance(), "com.sun.imageio.plugins.jpeg.JPEGImageReaderSpi", ImageReaderSpi.class);
|
return lookupProviderByName(IIORegistry.getDefaultInstance(), "com.sun.imageio.plugins.jpeg.JPEGImageReaderSpi", ImageReaderSpi.class);
|
||||||
@@ -133,26 +140,6 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
// More test data in specific tests below
|
// More test data in specific tests below
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ImageReaderSpi createProvider() {
|
|
||||||
return SPI;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected JPEGImageReader createReader() {
|
|
||||||
try {
|
|
||||||
return (JPEGImageReader) SPI.createReaderInstance();
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class<JPEGImageReader> getReaderClass() {
|
|
||||||
return JPEGImageReader.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean allowsNullRawImageType() {
|
protected boolean allowsNullRawImageType() {
|
||||||
return true;
|
return true;
|
||||||
@@ -182,26 +169,30 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
public void testICCProfileCMYKClassOutputColors() throws IOException {
|
public void testICCProfileCMYKClassOutputColors() throws IOException {
|
||||||
// Make sure ICC profile with class output isn't converted to too bright values
|
// Make sure ICC profile with class output isn't converted to too bright values
|
||||||
JPEGImageReader reader = createReader();
|
JPEGImageReader reader = createReader();
|
||||||
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/cmyk-sample-custom-icc-bright.jpg")));
|
|
||||||
|
|
||||||
ImageReadParam param = reader.getDefaultReadParam();
|
try (ImageInputStream stream = ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/cmyk-sample-custom-icc-bright.jpg"))) {
|
||||||
param.setSourceRegion(new Rectangle(800, 800, 64, 8));
|
reader.setInput(stream);
|
||||||
param.setSourceSubsampling(8, 8, 2, 2);
|
|
||||||
|
|
||||||
BufferedImage image = reader.read(0, param);
|
ImageReadParam param = reader.getDefaultReadParam();
|
||||||
assertNotNull(image);
|
param.setSourceRegion(new Rectangle(800, 800, 64, 8));
|
||||||
|
param.setSourceSubsampling(8, 8, 2, 2);
|
||||||
|
|
||||||
byte[] data = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
|
BufferedImage image = reader.read(0, param);
|
||||||
byte[] expectedData = {34, 37, 34, 47, 47, 44, 22, 26, 28, 23, 26, 28, 20, 23, 26, 20, 22, 25, 22, 25, 27, 18, 21, 24};
|
assertNotNull(image);
|
||||||
|
|
||||||
assertEquals(expectedData.length, data.length);
|
byte[] data = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
|
||||||
|
byte[] expectedData = {34, 37, 34, 47, 47, 44, 22, 26, 28, 23, 26, 28, 20, 23, 26, 20, 22, 25, 22, 25, 27, 18, 21, 24};
|
||||||
|
|
||||||
assertJPEGPixelsEqual(expectedData, data, 0);
|
assertEquals(expectedData.length, data.length);
|
||||||
|
|
||||||
reader.dispose();
|
assertJPEGPixelsEqual(expectedData, data, 0);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
reader.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void assertJPEGPixelsEqual(byte[] expected, byte[] actual, int actualOffset) {
|
private static void assertJPEGPixelsEqual(byte[] expected, byte[] actual, @SuppressWarnings("SameParameterValue") int actualOffset) {
|
||||||
for (int i = 0; i < expected.length; i++) {
|
for (int i = 0; i < expected.length; i++) {
|
||||||
assertEquals(String.format("Difference in pixel %d", i), expected[i], actual[i + actualOffset], 5);
|
assertEquals(String.format("Difference in pixel %d", i), expected[i], actual[i + actualOffset], 5);
|
||||||
}
|
}
|
||||||
@@ -211,38 +202,44 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
public void testICCDuplicateSequence() throws IOException {
|
public void testICCDuplicateSequence() throws IOException {
|
||||||
// Variation of the above, file contains multiple ICC chunks, with all counts and sequence numbers == 1
|
// Variation of the above, file contains multiple ICC chunks, with all counts and sequence numbers == 1
|
||||||
JPEGImageReader reader = createReader();
|
JPEGImageReader reader = createReader();
|
||||||
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/invalid-icc-duplicate-sequence-numbers-rgb-internal-kodak-srgb-jfif.jpg")));
|
try (ImageInputStream stream = ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/invalid-icc-duplicate-sequence-numbers-rgb-internal-kodak-srgb-jfif.jpg"))) {
|
||||||
|
reader.setInput(stream);
|
||||||
|
|
||||||
assertEquals(345, reader.getWidth(0));
|
assertEquals(345, reader.getWidth(0));
|
||||||
assertEquals(540, reader.getHeight(0));
|
assertEquals(540, reader.getHeight(0));
|
||||||
|
|
||||||
BufferedImage image = reader.read(0);
|
BufferedImage image = reader.read(0);
|
||||||
|
|
||||||
assertNotNull(image);
|
assertNotNull(image);
|
||||||
assertEquals(345, image.getWidth());
|
assertEquals(345, image.getWidth());
|
||||||
assertEquals(540, image.getHeight());
|
assertEquals(540, image.getHeight());
|
||||||
|
}
|
||||||
reader.dispose();
|
finally {
|
||||||
|
reader.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testICCDuplicateSequenceZeroBased() throws IOException {
|
public void testICCDuplicateSequenceZeroBased() throws IOException {
|
||||||
// File contains multiple ICC chunks, with all counts and sequence numbers == 0
|
// File contains multiple ICC chunks, with all counts and sequence numbers == 0
|
||||||
JPEGImageReader reader = createReader();
|
JPEGImageReader reader = createReader();
|
||||||
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/invalid-icc-duplicate-sequence-numbers-rgb-xerox-dc250-heavyweight-1-progressive-jfif.jpg")));
|
try (ImageInputStream stream = ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/invalid-icc-duplicate-sequence-numbers-rgb-xerox-dc250-heavyweight-1-progressive-jfif.jpg"))) {
|
||||||
|
reader.setInput(stream);
|
||||||
|
|
||||||
assertEquals(3874, reader.getWidth(0));
|
assertEquals(3874, reader.getWidth(0));
|
||||||
assertEquals(5480, reader.getHeight(0));
|
assertEquals(5480, reader.getHeight(0));
|
||||||
|
|
||||||
ImageReadParam param = reader.getDefaultReadParam();
|
ImageReadParam param = reader.getDefaultReadParam();
|
||||||
param.setSourceRegion(new Rectangle(0, 0, 3874, 16)); // Save some memory
|
param.setSourceRegion(new Rectangle(0, 0, 3874, 16)); // Save some memory
|
||||||
BufferedImage image = reader.read(0, param);
|
BufferedImage image = reader.read(0, param);
|
||||||
|
|
||||||
assertNotNull(image);
|
assertNotNull(image);
|
||||||
assertEquals(3874, image.getWidth());
|
assertEquals(3874, image.getWidth());
|
||||||
assertEquals(16, image.getHeight());
|
assertEquals(16, image.getHeight());
|
||||||
|
}
|
||||||
reader.dispose();
|
finally {
|
||||||
|
reader.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -251,20 +248,23 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
// Profile should have been about 550 000 bytes, split into multiple chunks. Written by GIMP 2.6.11
|
// Profile should have been about 550 000 bytes, split into multiple chunks. Written by GIMP 2.6.11
|
||||||
// See: https://bugzilla.redhat.com/show_bug.cgi?id=695246
|
// See: https://bugzilla.redhat.com/show_bug.cgi?id=695246
|
||||||
JPEGImageReader reader = createReader();
|
JPEGImageReader reader = createReader();
|
||||||
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/cmm-exception-invalid-icc-profile-data.jpg")));
|
try (ImageInputStream stream = ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/cmm-exception-invalid-icc-profile-data.jpg"))) {
|
||||||
|
reader.setInput(stream);
|
||||||
|
|
||||||
assertEquals(1993, reader.getWidth(0));
|
assertEquals(1993, reader.getWidth(0));
|
||||||
assertEquals(1038, reader.getHeight(0));
|
assertEquals(1038, reader.getHeight(0));
|
||||||
|
|
||||||
ImageReadParam param = reader.getDefaultReadParam();
|
ImageReadParam param = reader.getDefaultReadParam();
|
||||||
param.setSourceRegion(new Rectangle(reader.getWidth(0), 8));
|
param.setSourceRegion(new Rectangle(reader.getWidth(0), 8));
|
||||||
BufferedImage image = reader.read(0, param);
|
BufferedImage image = reader.read(0, param);
|
||||||
|
|
||||||
assertNotNull(image);
|
assertNotNull(image);
|
||||||
assertEquals(1993, image.getWidth());
|
assertEquals(1993, image.getWidth());
|
||||||
assertEquals(8, image.getHeight());
|
assertEquals(8, image.getHeight());
|
||||||
|
}
|
||||||
reader.dispose();
|
finally {
|
||||||
|
reader.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -272,19 +272,23 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
// File contains CMYK ICC profile ("Coated FOGRA27 (ISO 12647-2:2004)"), but image data is 3 channel YCC/RGB
|
// File contains CMYK ICC profile ("Coated FOGRA27 (ISO 12647-2:2004)"), but image data is 3 channel YCC/RGB
|
||||||
// JFIF 1.1 with unknown origin.
|
// JFIF 1.1 with unknown origin.
|
||||||
JPEGImageReader reader = createReader();
|
JPEGImageReader reader = createReader();
|
||||||
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/cco-illegalargument-rgb-coated-fogra27.jpg")));
|
try (ImageInputStream stream = ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/cco-illegalargument-rgb-coated-fogra27.jpg"))) {
|
||||||
|
reader.setInput(stream);
|
||||||
|
|
||||||
assertEquals(281, reader.getWidth(0));
|
assertEquals(281, reader.getWidth(0));
|
||||||
assertEquals(449, reader.getHeight(0));
|
assertEquals(449, reader.getHeight(0));
|
||||||
|
|
||||||
BufferedImage image = reader.read(0);
|
BufferedImage image = reader.read(0);
|
||||||
|
|
||||||
assertNotNull(image);
|
assertNotNull(image);
|
||||||
assertEquals(281, image.getWidth());
|
assertEquals(281, image.getWidth());
|
||||||
assertEquals(449, image.getHeight());
|
assertEquals(449, image.getHeight());
|
||||||
|
|
||||||
// TODO: Need to test colors!
|
// TODO: Need to test colors!
|
||||||
reader.dispose();
|
}
|
||||||
|
finally {
|
||||||
|
reader.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -293,22 +297,27 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
// but image data is plain 3 channel YCC/RGB.
|
// but image data is plain 3 channel YCC/RGB.
|
||||||
// EXIF/TIFF metadata says Software: "Microsoft Windows Photo Gallery 6.0.6001.18000"...
|
// EXIF/TIFF metadata says Software: "Microsoft Windows Photo Gallery 6.0.6001.18000"...
|
||||||
JPEGImageReader reader = createReader();
|
JPEGImageReader reader = createReader();
|
||||||
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/no-image-types-rgb-us-web-coated-v2-ms-photogallery-exif.jpg")));
|
try (ImageInputStream stream = ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/no-image-types-rgb-us-web-coated-v2-ms-photogallery-exif.jpg"))) {
|
||||||
|
reader.setInput(stream);
|
||||||
|
|
||||||
assertEquals(1743, reader.getWidth(0));
|
assertEquals(1743, reader.getWidth(0));
|
||||||
assertEquals(2551, reader.getHeight(0));
|
assertEquals(2551, reader.getHeight(0));
|
||||||
|
|
||||||
ImageReadParam param = reader.getDefaultReadParam();
|
ImageReadParam param = reader.getDefaultReadParam();
|
||||||
param.setSourceRegion(new Rectangle(0, 0, 1743, 16)); // Save some memory
|
param.setSourceRegion(new Rectangle(0, 0, 1743, 16)); // Save some memory
|
||||||
BufferedImage image = reader.read(0, param);
|
BufferedImage image = reader.read(0, param);
|
||||||
|
|
||||||
assertNotNull(image);
|
assertNotNull(image);
|
||||||
assertEquals(1743, image.getWidth());
|
assertEquals(1743, image.getWidth());
|
||||||
assertEquals(16, image.getHeight());
|
assertEquals(16, image.getHeight());
|
||||||
|
|
||||||
// TODO: Need to test colors!
|
// TODO: Need to test colors!
|
||||||
|
|
||||||
assertTrue(reader.hasThumbnails(0)); // Should not blow up!
|
assertTrue(reader.hasThumbnails(0)); // Should not blow up!
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
reader.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -316,107 +325,131 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
// File contains JFIF (!), RGB ICC profile AND Adobe App14 specifying unknown conversion,
|
// File contains JFIF (!), RGB ICC profile AND Adobe App14 specifying unknown conversion,
|
||||||
// but image data is 4 channel CMYK (from SOF0 channel Ids 'C', 'M', 'Y', 'K').
|
// but image data is 4 channel CMYK (from SOF0 channel Ids 'C', 'M', 'Y', 'K').
|
||||||
JPEGImageReader reader = createReader();
|
JPEGImageReader reader = createReader();
|
||||||
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/jfif-cmyk-invalid-icc-profile-srgb.jpg")));
|
try (ImageInputStream stream = ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/jfif-cmyk-invalid-icc-profile-srgb.jpg"))) {
|
||||||
|
reader.setInput(stream);
|
||||||
|
|
||||||
assertEquals(493, reader.getWidth(0));
|
assertEquals(493, reader.getWidth(0));
|
||||||
assertEquals(500, reader.getHeight(0));
|
assertEquals(500, reader.getHeight(0));
|
||||||
|
|
||||||
ImageReadParam param = reader.getDefaultReadParam();
|
ImageReadParam param = reader.getDefaultReadParam();
|
||||||
param.setSourceRegion(new Rectangle(0, 0, 493, 16)); // Save some memory
|
param.setSourceRegion(new Rectangle(0, 0, 493, 16)); // Save some memory
|
||||||
BufferedImage image = reader.read(0, param);
|
BufferedImage image = reader.read(0, param);
|
||||||
|
|
||||||
assertNotNull(image);
|
assertNotNull(image);
|
||||||
assertEquals(493, image.getWidth());
|
assertEquals(493, image.getWidth());
|
||||||
assertEquals(16, image.getHeight());
|
assertEquals(16, image.getHeight());
|
||||||
|
|
||||||
// TODO: Need to test colors!
|
// TODO: Need to test colors!
|
||||||
|
|
||||||
assertFalse(reader.hasThumbnails(0)); // Should not blow up!
|
assertFalse(reader.hasThumbnails(0)); // Should not blow up!
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
reader.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWarningEmbeddedColorProfileInvalidIgnored() throws IOException {
|
public void testWarningEmbeddedColorProfileInvalidIgnored() throws IOException {
|
||||||
JPEGImageReader reader = createReader();
|
JPEGImageReader reader = createReader();
|
||||||
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/warning-embedded-color-profile-invalid-ignored-cmyk.jpg")));
|
try (ImageInputStream stream = ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/warning-embedded-color-profile-invalid-ignored-cmyk.jpg"))) {
|
||||||
|
reader.setInput(stream);
|
||||||
|
|
||||||
assertEquals(183, reader.getWidth(0));
|
assertEquals(183, reader.getWidth(0));
|
||||||
assertEquals(283, reader.getHeight(0));
|
assertEquals(283, reader.getHeight(0));
|
||||||
|
|
||||||
BufferedImage image = reader.read(0);
|
BufferedImage image = reader.read(0);
|
||||||
|
|
||||||
assertNotNull(image);
|
assertNotNull(image);
|
||||||
assertEquals(183, image.getWidth());
|
assertEquals(183, image.getWidth());
|
||||||
assertEquals(283, image.getHeight());
|
assertEquals(283, image.getHeight());
|
||||||
|
|
||||||
// TODO: Need to test colors!
|
// TODO: Need to test colors!
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
reader.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEOFSOSSegment() throws IOException {
|
public void testEOFSOSSegment() throws IOException {
|
||||||
// Regression...
|
// Regression...
|
||||||
JPEGImageReader reader = createReader();
|
JPEGImageReader reader = createReader();
|
||||||
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/eof-sos-segment-bug.jpg")));
|
try (ImageInputStream stream = ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/eof-sos-segment-bug.jpg"))) {
|
||||||
|
reader.setInput(stream);
|
||||||
|
|
||||||
assertEquals(266, reader.getWidth(0));
|
assertEquals(266, reader.getWidth(0));
|
||||||
assertEquals(400, reader.getHeight(0));
|
assertEquals(400, reader.getHeight(0));
|
||||||
|
|
||||||
BufferedImage image = reader.read(0);
|
BufferedImage image = reader.read(0);
|
||||||
|
|
||||||
assertNotNull(image);
|
assertNotNull(image);
|
||||||
assertEquals(266, image.getWidth());
|
assertEquals(266, image.getWidth());
|
||||||
assertEquals(400, image.getHeight());
|
assertEquals(400, image.getHeight());
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
reader.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInvalidICCSingleChunkBadSequence() throws IOException {
|
public void testInvalidICCSingleChunkBadSequence() throws IOException {
|
||||||
// Regression
|
// Regression
|
||||||
// Single segment ICC profile, with chunk index/count == 0
|
// Single segment ICC profile, with chunk index/count == 0
|
||||||
|
|
||||||
JPEGImageReader reader = createReader();
|
JPEGImageReader reader = createReader();
|
||||||
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/invalid-icc-single-chunk-bad-sequence-number.jpg")));
|
try (ImageInputStream stream = ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/invalid-icc-single-chunk-bad-sequence-number.jpg"))) {
|
||||||
|
reader.setInput(stream);
|
||||||
|
|
||||||
assertEquals(1772, reader.getWidth(0));
|
assertEquals(1772, reader.getWidth(0));
|
||||||
assertEquals(2126, reader.getHeight(0));
|
assertEquals(2126, reader.getHeight(0));
|
||||||
|
|
||||||
ImageReadParam param = reader.getDefaultReadParam();
|
ImageReadParam param = reader.getDefaultReadParam();
|
||||||
param.setSourceRegion(new Rectangle(reader.getWidth(0), 8));
|
param.setSourceRegion(new Rectangle(reader.getWidth(0), 8));
|
||||||
|
|
||||||
IIOReadWarningListener warningListener = mock(IIOReadWarningListener.class);
|
IIOReadWarningListener warningListener = mock(IIOReadWarningListener.class);
|
||||||
reader.addIIOReadWarningListener(warningListener);
|
reader.addIIOReadWarningListener(warningListener);
|
||||||
|
|
||||||
BufferedImage image = reader.read(0, param);
|
BufferedImage image = reader.read(0, param);
|
||||||
|
|
||||||
assertNotNull(image);
|
assertNotNull(image);
|
||||||
assertEquals(1772, image.getWidth());
|
assertEquals(1772, image.getWidth());
|
||||||
assertEquals(8, image.getHeight());
|
assertEquals(8, image.getHeight());
|
||||||
|
|
||||||
verify(warningListener, atLeast(1)).warningOccurred(eq(reader), anyString());
|
verify(warningListener, atLeast(1)).warningOccurred(eq(reader), anyString());
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
reader.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testYCbCrNotSubsampledNonstandardChannelIndexes() throws IOException {
|
public void testYCbCrNotSubsampledNonstandardChannelIndexes() throws IOException {
|
||||||
// Regression: Make sure 3 channel, non-subsampled JFIF, defaults to YCbCr, even if unstandard channel indexes
|
// Regression: Make sure 3 channel, non-subsampled JFIF, defaults to YCbCr, even if unstandard channel indexes
|
||||||
JPEGImageReader reader = createReader();
|
JPEGImageReader reader = createReader();
|
||||||
reader.setInput(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);
|
||||||
|
|
||||||
assertEquals(600, reader.getWidth(0));
|
assertEquals(600, reader.getWidth(0));
|
||||||
assertEquals(600, reader.getHeight(0));
|
assertEquals(600, reader.getHeight(0));
|
||||||
|
|
||||||
ImageReadParam param = reader.getDefaultReadParam();
|
ImageReadParam param = reader.getDefaultReadParam();
|
||||||
param.setSourceRegion(new Rectangle(8, 8));
|
param.setSourceRegion(new Rectangle(8, 8));
|
||||||
|
|
||||||
BufferedImage image = reader.read(0, param);
|
BufferedImage image = reader.read(0, param);
|
||||||
|
|
||||||
assertNotNull(image);
|
assertNotNull(image);
|
||||||
assertEquals(8, image.getWidth());
|
assertEquals(8, image.getWidth());
|
||||||
assertEquals(8, image.getHeight());
|
assertEquals(8, image.getHeight());
|
||||||
|
|
||||||
// QnD test: Make sure all pixels are white (if treated as RGB, they will be pink-ish)
|
// QnD test: Make sure all pixels are white (if treated as RGB, they will be pink-ish)
|
||||||
for (int y = 0; y < image.getHeight(); y++) {
|
for (int y = 0; y < image.getHeight(); y++) {
|
||||||
for (int x = 0; x < image.getWidth(); x++) {
|
for (int x = 0; x < image.getWidth(); x++) {
|
||||||
assertEquals(0xffffff, image.getRGB(x, y) & 0xffffff);
|
assertEquals(0xffffff, image.getRGB(x, y) & 0xffffff);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
|
reader.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -424,32 +457,83 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
// Special case, throws exception below without special treatment
|
// Special case, throws exception below without special treatment
|
||||||
// java.awt.color.CMMException: General CMM error517
|
// java.awt.color.CMMException: General CMM error517
|
||||||
JPEGImageReader reader = createReader();
|
JPEGImageReader reader = createReader();
|
||||||
reader.setInput(ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/cmm-exception-corbis-rgb.jpg")));
|
try (ImageInputStream stream = ImageIO.createImageInputStream(getClassLoaderResource("/jpeg/cmm-exception-corbis-rgb.jpg"))) {
|
||||||
|
reader.setInput(stream);
|
||||||
|
|
||||||
assertEquals(512, reader.getWidth(0));
|
assertEquals(512, reader.getWidth(0));
|
||||||
assertEquals(384, reader.getHeight(0));
|
assertEquals(384, reader.getHeight(0));
|
||||||
|
|
||||||
BufferedImage image = reader.read(0);
|
BufferedImage image = reader.read(0);
|
||||||
|
|
||||||
assertNotNull(image);
|
assertNotNull(image);
|
||||||
assertEquals(512, image.getWidth());
|
assertEquals(512, image.getWidth());
|
||||||
assertEquals(384, image.getHeight());
|
assertEquals(384, image.getHeight());
|
||||||
|
}
|
||||||
reader.dispose();
|
finally {
|
||||||
|
reader.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore("Known issue in com.sun...JPEGMetadata")
|
|
||||||
@Test
|
@Test
|
||||||
public void testStandardMetadataColorSpaceTypeRGBForYCbCr() {
|
public void testStandardMetadataColorSpaceTypeRGBForYCbCr() throws IOException {
|
||||||
// These reports RGB in standard metadata, while the data is really YCbCr.
|
List<TestData> ycbcr = Arrays.asList(
|
||||||
// Exif files are always YCbCr AFAIK.
|
// This reports RGB in standard metadata, while the data is really YCbCr.
|
||||||
fail("/jpeg/exif-jpeg-thumbnail-sony-dsc-p150-inverted-colors.jpg");
|
// Exif files are always YCbCr AFAIK.
|
||||||
fail("/jpeg/exif-pspro-13-inverted-colors.jpg");
|
new TestData(getClassLoaderResource("/jpeg/exif-jpeg-thumbnail-sony-dsc-p150-inverted-colors.jpg"), new Dimension(2437, 1662)),
|
||||||
// Not Exif, but same issue: SOF comp ids are JFIF standard 1-3 and
|
// Not Exif, but same issue: SOF comp ids are JFIF standard 1-3 and
|
||||||
// *should* be interpreted as YCbCr but isn't.
|
// *should* be interpreted as YCbCr but isn't.
|
||||||
// Possible fix for this, is to insert a fake JFIF segment, as this image
|
// Possible fix for this, is to insert a fake JFIF segment, as this image
|
||||||
// conforms to the JFIF spec (but it won't work for the Exif samples)
|
// conforms to the JFIF spec (but it won't work for the Exif samples)
|
||||||
fail("/jpeg/no-jfif-ycbcr.jpg");
|
new TestData(getClassLoaderResource("/jpeg/no-jfif-ycbcr.jpg"), new Dimension(310, 206))
|
||||||
|
);
|
||||||
|
|
||||||
|
JPEGImageReader reader = createReader();
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (TestData broken : ycbcr) {
|
||||||
|
reader.setInput(broken.getInputStream());
|
||||||
|
|
||||||
|
IIOMetadata metadata = reader.getImageMetadata(0);
|
||||||
|
|
||||||
|
IIOMetadataNode root = (IIOMetadataNode) metadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
|
||||||
|
NodeList colorSpaceTypes = root.getElementsByTagName("ColorSpaceType");
|
||||||
|
assertEquals(1, colorSpaceTypes.getLength());
|
||||||
|
IIOMetadataNode csType = (IIOMetadataNode) colorSpaceTypes.item(0);
|
||||||
|
assertEquals("YCbCr", csType.getAttribute("name"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
reader.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetExifOrientationFromMetadata() throws IOException {
|
||||||
|
JPEGImageReader reader = createReader();
|
||||||
|
|
||||||
|
// TODO: Find better sample data. Should have an uppercase F ;-)
|
||||||
|
// Test all 9 mutations + missing Exif
|
||||||
|
List<String> expectedOrientations = Arrays.asList("Normal", "Normal", "FlipH", "Rotate180", "FlipV", "FlipVRotate90", "Rotate270", "FlipHRotate90", "Rotate90");
|
||||||
|
try {
|
||||||
|
for (int i = 0; i < 9; i++) {
|
||||||
|
try (ImageInputStream stream = ImageIO.createImageInputStream(getClassLoaderResource(String.format("/exif/Landscape_%d.jpg", i)))) {
|
||||||
|
reader.setInput(stream);
|
||||||
|
|
||||||
|
IIOMetadata metadata = reader.getImageMetadata(0);
|
||||||
|
IIOMetadataNode root = (IIOMetadataNode) metadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
|
||||||
|
|
||||||
|
NodeList orientationNodes = root.getElementsByTagName("ImageOrientation");
|
||||||
|
assertEquals(1, orientationNodes.getLength());
|
||||||
|
|
||||||
|
IIOMetadataNode orientationNode = (IIOMetadataNode) orientationNodes.item(0);
|
||||||
|
String orientationValue = orientationNode.getAttribute("value");
|
||||||
|
assertEquals(expectedOrientations.get(i), orientationValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
reader.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -488,7 +572,6 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
public void testSPIRecognizesBrokenJPEG() throws IOException {
|
public void testSPIRecognizesBrokenJPEG() throws IOException {
|
||||||
// TODO: There's a bug in com.sun.imageio.plugins.png.PNGImageReaderSpi.canDecode
|
// TODO: There's a bug in com.sun.imageio.plugins.png.PNGImageReaderSpi.canDecode
|
||||||
// causing files < 8 bytes to not be recognized as anything...
|
// causing files < 8 bytes to not be recognized as anything...
|
||||||
ImageReaderSpi provider = createProvider();
|
|
||||||
for (TestData data : getBrokenTestData()) {
|
for (TestData data : getBrokenTestData()) {
|
||||||
assertTrue(data.toString(), provider.canDecodeInput(data.getInputStream()));
|
assertTrue(data.toString(), provider.canDecodeInput(data.getInputStream()));
|
||||||
}
|
}
|
||||||
@@ -1284,6 +1367,9 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
|
|
||||||
// Assume that the aspect ratio is 1 if both x/y density is 0.
|
// Assume that the aspect ratio is 1 if both x/y density is 0.
|
||||||
IIOMetadataNode tree = (IIOMetadataNode) imageMetadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
|
IIOMetadataNode tree = (IIOMetadataNode) imageMetadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
|
||||||
|
|
||||||
|
// new XMLSerializer(System.out, System.getProperty("file.encoding")).serialize(imageMetadata.getAsTree(imageMetadata.getNativeMetadataFormatName()), false);
|
||||||
|
// new XMLSerializer(System.out, System.getProperty("file.encoding")).serialize(tree, false);
|
||||||
NodeList dimensions = tree.getElementsByTagName("Dimension");
|
NodeList dimensions = tree.getElementsByTagName("Dimension");
|
||||||
assertEquals(1, dimensions.getLength());
|
assertEquals(1, dimensions.getLength());
|
||||||
assertEquals("PixelAspectRatio", dimensions.item(0).getFirstChild().getNodeName());
|
assertEquals("PixelAspectRatio", dimensions.item(0).getFirstChild().getNodeName());
|
||||||
@@ -1321,7 +1407,7 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
|
|
||||||
NodeList markerSequences = iioTree.getElementsByTagName("markerSequence");
|
NodeList markerSequences = iioTree.getElementsByTagName("markerSequence");
|
||||||
assertTrue(markerSequences.getLength() == 1 || markerSequences.getLength() == 2); // In case of JPEG encoded thumbnail, there will be 2
|
assertTrue(markerSequences.getLength() == 1 || markerSequences.getLength() == 2); // In case of JPEG encoded thumbnail, there will be 2
|
||||||
IIOMetadataNode markerSequence = (IIOMetadataNode) markerSequences.item(0);
|
IIOMetadataNode markerSequence = (IIOMetadataNode) markerSequences.item(markerSequences.getLength() - 1); // The last will be the "main" image
|
||||||
assertNotNull(markerSequence);
|
assertNotNull(markerSequence);
|
||||||
assertThat(markerSequence.getChildNodes().getLength(), new GreaterThan<>(0));
|
assertThat(markerSequence.getChildNodes().getLength(), new GreaterThan<>(0));
|
||||||
|
|
||||||
@@ -1379,6 +1465,7 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
|
|
||||||
for (TestData testData : getTestData()) {
|
for (TestData testData : getTestData()) {
|
||||||
reader.setInput(testData.getInputStream());
|
reader.setInput(testData.getInputStream());
|
||||||
|
assert referenceReader != null;
|
||||||
referenceReader.setInput(testData.getInputStream());
|
referenceReader.setInput(testData.getInputStream());
|
||||||
|
|
||||||
for (int i = 0; i < reader.getNumImages(true); i++) {
|
for (int i = 0; i < reader.getNumImages(true); i++) {
|
||||||
@@ -1393,6 +1480,8 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
Node referenceTree = reference.getAsTree(formatName);
|
Node referenceTree = reference.getAsTree(formatName);
|
||||||
Node actualTree = metadata.getAsTree(formatName);
|
Node actualTree = metadata.getAsTree(formatName);
|
||||||
|
|
||||||
|
// new XMLSerializer(System.out, System.getProperty("file.encoding")).serialize(referenceTree, false);
|
||||||
|
// System.out.println("--------");
|
||||||
// new XMLSerializer(System.out, System.getProperty("file.encoding")).serialize(actualTree, false);
|
// new XMLSerializer(System.out, System.getProperty("file.encoding")).serialize(actualTree, false);
|
||||||
assertTreesEquals(String.format("Metadata differs for %s image %s ", testData, i), referenceTree, actualTree);
|
assertTreesEquals(String.format("Metadata differs for %s image %s ", testData, i), referenceTree, actualTree);
|
||||||
}
|
}
|
||||||
@@ -1401,9 +1490,9 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
throw new AssertionError(String.format("Reading metadata failed for %s image %s: %s", testData, i, e.getMessage()), e);
|
throw new AssertionError(String.format("Reading metadata failed for %s image %s: %s", testData, i, e.getMessage()), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IIOException ignore) {
|
catch (IIOException warn) {
|
||||||
// The reference reader will fail on certain images, we'll just ignore that
|
// The reference reader will fail on certain images, we'll just ignore that
|
||||||
System.err.println(String.format("WARNING: Reading reference metadata failed for %s image %s: %s", testData, i, ignore.getMessage()));
|
System.err.printf("WARNING: Reading reference metadata failed for %s image %s: %s%n", testData, i, warn.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1432,8 +1521,7 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (expectedTree == null) {
|
if (expectedTree == null) {
|
||||||
assertNull(actualTree);
|
fail("Expected tree is null, actual tree is non-null");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assertEquals(String.format("%s: Node names differ", message), expectedTree.getNodeName(), actualTree.getNodeName());
|
assertEquals(String.format("%s: Node names differ", message), expectedTree.getNodeName(), actualTree.getNodeName());
|
||||||
@@ -1443,7 +1531,14 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
assertEquals(String.format("%s: Number of attributes for <%s> differ", message, expectedTree.getNodeName()), expectedAttributes.getLength(), actualAttributes.getLength());
|
assertEquals(String.format("%s: Number of attributes for <%s> differ", message, expectedTree.getNodeName()), expectedAttributes.getLength(), actualAttributes.getLength());
|
||||||
for (int i = 0; i < expectedAttributes.getLength(); i++) {
|
for (int i = 0; i < expectedAttributes.getLength(); i++) {
|
||||||
Node item = expectedAttributes.item(i);
|
Node item = expectedAttributes.item(i);
|
||||||
assertEquals(String.format("%s: \"%s\" attribute for <%s> differ", message, item.getNodeName(), expectedTree.getNodeName()), item.getNodeValue(), actualAttributes.getNamedItem(item.getNodeName()).getNodeValue());
|
String nodeValue = item.getNodeValue();
|
||||||
|
|
||||||
|
// NOTE: com.sun...JPEGMetadata javax_imageio_1.0 format bug: Uses "normal" instead of "Normal" ImageOrientation
|
||||||
|
if ("ImageOrientation".equals(expectedTree.getNodeName()) && "value".equals(item.getNodeName())) {
|
||||||
|
nodeValue = StringUtil.capitalize(nodeValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(String.format("%s: \"%s\" attribute for <%s> differ", message, item.getNodeName(), expectedTree.getNodeName()), nodeValue, actualAttributes.getNamedItem(item.getNodeName()).getNodeValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test for equal user objects.
|
// Test for equal user objects.
|
||||||
@@ -1460,6 +1555,11 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ("markerSequence".equals(expectedTree.getNodeName()) && "JFIFthumbJPEG".equals(expectedTree.getParentNode().getNodeName())) {
|
||||||
|
// TODO: We haven't implemented this yet
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Sort nodes to make sure that sequence of equally named tags does not matter
|
// Sort nodes to make sure that sequence of equally named tags does not matter
|
||||||
List<IIOMetadataNode> expectedChildren = sortNodes(expectedTree.getChildNodes());
|
List<IIOMetadataNode> expectedChildren = sortNodes(expectedTree.getChildNodes());
|
||||||
List<IIOMetadataNode> actualChildren = sortNodes(actualTree.getChildNodes());
|
List<IIOMetadataNode> actualChildren = sortNodes(actualTree.getChildNodes());
|
||||||
@@ -1861,4 +1961,36 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
reader.dispose();
|
reader.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 1000L)
|
||||||
|
public void testInfiniteLoopCorrupt() throws IOException {
|
||||||
|
ImageReader reader = createReader();
|
||||||
|
|
||||||
|
try (ImageInputStream iis = ImageIO.createImageInputStream(getClassLoaderResource("/broken-jpeg/110115680-6d6dce80-7d84-11eb-99df-4cb21df3b09f.jpeg"))) {
|
||||||
|
reader.setInput(iis);
|
||||||
|
|
||||||
|
try {
|
||||||
|
reader.read(0, null);
|
||||||
|
}
|
||||||
|
catch (IIOException expected) {
|
||||||
|
assertThat(expected.getMessage(), allOf(containsString("SOF"), containsString("stream")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(timeout = 1000L)
|
||||||
|
public void testInfiniteLoopCorruptRaster() throws IOException {
|
||||||
|
ImageReader reader = createReader();
|
||||||
|
|
||||||
|
try (ImageInputStream iis = ImageIO.createImageInputStream(getClassLoaderResource("/broken-jpeg/110115680-6d6dce80-7d84-11eb-99df-4cb21df3b09f.jpeg"))) {
|
||||||
|
reader.setInput(iis);
|
||||||
|
|
||||||
|
try {
|
||||||
|
reader.readRaster(0, null);
|
||||||
|
}
|
||||||
|
catch (IIOException expected) {
|
||||||
|
assertThat(expected.getMessage(), allOf(containsString("SOF"), containsString("stream")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ package com.twelvemonkeys.imageio.plugins.jpeg;
|
|||||||
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
||||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||||
import com.twelvemonkeys.imageio.util.ImageWriterAbstractTest;
|
import com.twelvemonkeys.imageio.util.ImageWriterAbstractTest;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
|
|
||||||
@@ -47,17 +48,23 @@ import javax.imageio.stream.ImageOutputStream;
|
|||||||
import javax.imageio.stream.MemoryCacheImageOutputStream;
|
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.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.awt.image.ComponentColorModel;
|
||||||
|
import java.awt.image.DataBuffer;
|
||||||
import java.awt.image.RenderedImage;
|
import java.awt.image.RenderedImage;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JPEGImageWriterTest
|
* JPEGImageWriterTest
|
||||||
@@ -66,22 +73,14 @@ import static org.junit.Assert.assertNotNull;
|
|||||||
* @author last modified by $Author: haraldk$
|
* @author last modified by $Author: haraldk$
|
||||||
* @version $Id: JPEGImageWriterTest.java,v 1.0 06.02.12 17:05 haraldk Exp$
|
* @version $Id: JPEGImageWriterTest.java,v 1.0 06.02.12 17:05 haraldk Exp$
|
||||||
*/
|
*/
|
||||||
public class JPEGImageWriterTest extends ImageWriterAbstractTest {
|
public class JPEGImageWriterTest extends ImageWriterAbstractTest<JPEGImageWriter> {
|
||||||
|
|
||||||
private static final JPEGImageWriterSpi SPI = new JPEGImageWriterSpi(lookupDelegateProvider());
|
|
||||||
|
|
||||||
private static ImageWriterSpi lookupDelegateProvider() {
|
private static ImageWriterSpi lookupDelegateProvider() {
|
||||||
return IIOUtil.lookupProviderByName(IIORegistry.getDefaultInstance(), "com.sun.imageio.plugins.jpeg.JPEGImageWriterSpi", ImageWriterSpi.class);
|
return IIOUtil.lookupProviderByName(IIORegistry.getDefaultInstance(), "com.sun.imageio.plugins.jpeg.JPEGImageWriterSpi", ImageWriterSpi.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ImageWriter createImageWriter() {
|
protected ImageWriterSpi createProvider() {
|
||||||
try {
|
return new JPEGImageWriterSpi(lookupDelegateProvider());
|
||||||
return SPI.createWriterInstance();
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -97,14 +96,18 @@ public class JPEGImageWriterTest extends ImageWriterAbstractTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReaderForWriter() {
|
public void testReaderForWriter() throws IOException {
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
ImageReader reader = ImageIO.getImageReader(writer);
|
ImageReader reader = ImageIO.getImageReader(writer);
|
||||||
assertNotNull(reader);
|
assertNotNull(reader);
|
||||||
assertEquals(writer.getClass().getPackage(), reader.getClass().getPackage());
|
assertEquals(writer.getClass().getPackage(), reader.getClass().getPackage());
|
||||||
}
|
}
|
||||||
|
|
||||||
private ByteArrayOutputStream transcode(final ImageReader reader, final URL resource, final ImageWriter writer, int outCSType) throws IOException {
|
private ByteArrayOutputStream transcode(final ImageReader reader, final URL resource, final ImageWriter writer, int outCSType) throws IOException {
|
||||||
|
return transcode(reader, resource, writer, outCSType, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ByteArrayOutputStream transcode(final ImageReader reader, final URL resource, final ImageWriter writer, int outCSType, boolean embedICCProfile) throws IOException {
|
||||||
try (ImageInputStream input = ImageIO.createImageInputStream(resource)) {
|
try (ImageInputStream input = ImageIO.createImageInputStream(resource)) {
|
||||||
reader.setInput(input);
|
reader.setInput(input);
|
||||||
ImageTypeSpecifier specifier = null;
|
ImageTypeSpecifier specifier = null;
|
||||||
@@ -125,6 +128,14 @@ public class JPEGImageWriterTest extends ImageWriterAbstractTest {
|
|||||||
readParam.setDestinationType(specifier);
|
readParam.setDestinationType(specifier);
|
||||||
IIOImage image = reader.readAll(0, readParam);
|
IIOImage image = reader.readAll(0, readParam);
|
||||||
|
|
||||||
|
if (!embedICCProfile) {
|
||||||
|
// Get rid of the color model/icc profile
|
||||||
|
ColorSpace fakeCS = mock(ColorSpace.class);
|
||||||
|
when(fakeCS.getType()).thenReturn(ColorSpace.TYPE_CMYK);
|
||||||
|
when(fakeCS.getNumComponents()).thenReturn(4);
|
||||||
|
specifier = new ImageTypeSpecifier(new ComponentColorModel(fakeCS, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE), image.getRenderedImage().getSampleModel());
|
||||||
|
}
|
||||||
|
|
||||||
// Write it back
|
// Write it back
|
||||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream(1024);
|
ByteArrayOutputStream bytes = new ByteArrayOutputStream(1024);
|
||||||
try (ImageOutputStream output = new MemoryCacheImageOutputStream(bytes)) {
|
try (ImageOutputStream output = new MemoryCacheImageOutputStream(bytes)) {
|
||||||
@@ -140,7 +151,7 @@ public class JPEGImageWriterTest extends ImageWriterAbstractTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTranscodeWithMetadataRGBtoRGB() throws IOException {
|
public void testTranscodeWithMetadataRGBtoRGB() throws IOException {
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
ImageReader reader = ImageIO.getImageReader(writer);
|
ImageReader reader = ImageIO.getImageReader(writer);
|
||||||
|
|
||||||
ByteArrayOutputStream stream = transcode(reader, getClassLoaderResource("/jpeg/jfif-jfxx-thumbnail-olympus-d320l.jpg"), writer, ColorSpace.TYPE_RGB);
|
ByteArrayOutputStream stream = transcode(reader, getClassLoaderResource("/jpeg/jfif-jfxx-thumbnail-olympus-d320l.jpg"), writer, ColorSpace.TYPE_RGB);
|
||||||
@@ -151,11 +162,18 @@ public class JPEGImageWriterTest extends ImageWriterAbstractTest {
|
|||||||
reader.setInput(new ByteArrayImageInputStream(stream.toByteArray()));
|
reader.setInput(new ByteArrayImageInputStream(stream.toByteArray()));
|
||||||
BufferedImage image = reader.read(0);
|
BufferedImage image = reader.read(0);
|
||||||
assertNotNull(image);
|
assertNotNull(image);
|
||||||
|
|
||||||
|
// Test color space type RGB (encoded as YCbCr) in standard metadata
|
||||||
|
IIOMetadata metadata = reader.getImageMetadata(0);
|
||||||
|
IIOMetadataNode standard = (IIOMetadataNode) metadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
|
||||||
|
NodeList colorSpaceType = standard.getElementsByTagName("ColorSpaceType");
|
||||||
|
assertEquals(1, colorSpaceType.getLength());
|
||||||
|
assertEquals("YCbCr", ((IIOMetadataNode) colorSpaceType.item(0)).getAttribute("name"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTranscodeWithMetadataCMYKtoCMYK() throws IOException {
|
public void testTranscodeWithMetadataCMYKtoCMYK() throws IOException {
|
||||||
ImageWriter writer = createImageWriter();
|
ImageWriter writer = createWriter();
|
||||||
ImageReader reader = ImageIO.getImageReader(writer);
|
ImageReader reader = ImageIO.getImageReader(writer);
|
||||||
|
|
||||||
ByteArrayOutputStream stream = transcode(reader, getClassLoaderResource("/jpeg/cmyk-sample-multiple-chunk-icc.jpg"), writer, ColorSpace.TYPE_CMYK);
|
ByteArrayOutputStream stream = transcode(reader, getClassLoaderResource("/jpeg/cmyk-sample-multiple-chunk-icc.jpg"), writer, ColorSpace.TYPE_CMYK);
|
||||||
@@ -168,11 +186,65 @@ public class JPEGImageWriterTest extends ImageWriterAbstractTest {
|
|||||||
assertEquals(100, image.getWidth());
|
assertEquals(100, image.getWidth());
|
||||||
assertEquals(100, image.getHeight());
|
assertEquals(100, image.getHeight());
|
||||||
|
|
||||||
|
// Test color space type CMYK in standard metadata
|
||||||
IIOMetadata metadata = reader.getImageMetadata(0);
|
IIOMetadata metadata = reader.getImageMetadata(0);
|
||||||
IIOMetadataNode standard = (IIOMetadataNode) metadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
|
IIOMetadataNode standard = (IIOMetadataNode) metadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
|
||||||
NodeList colorSpaceType = standard.getElementsByTagName("ColorSpaceType");
|
NodeList colorSpaceType = standard.getElementsByTagName("ColorSpaceType");
|
||||||
assertEquals(1, colorSpaceType.getLength());
|
assertEquals(1, colorSpaceType.getLength());
|
||||||
assertEquals("CMYK", ((IIOMetadataNode) colorSpaceType.item(0)).getAttribute("name"));
|
assertEquals("CMYK", ((IIOMetadataNode) colorSpaceType.item(0)).getAttribute("name"));
|
||||||
|
|
||||||
|
// Test APP2/ICC_PROFILE segments form native metadata
|
||||||
|
IIOMetadataNode nativeMeta = (IIOMetadataNode) metadata.getAsTree(JPEGImage10Metadata.JAVAX_IMAGEIO_JPEG_IMAGE_1_0);
|
||||||
|
NodeList unknown = nativeMeta.getElementsByTagName("unknown");
|
||||||
|
assertEquals(11, unknown.getLength()); // We write longer segments than the original, so we get less segments
|
||||||
|
|
||||||
|
ByteArrayOutputStream iccSegments = new ByteArrayOutputStream(1024 * 1024);
|
||||||
|
|
||||||
|
for (int i = 0; i < unknown.getLength(); i++) {
|
||||||
|
IIOMetadataNode node = (IIOMetadataNode) unknown.item(i);
|
||||||
|
byte[] data = (byte[]) node.getUserObject();
|
||||||
|
|
||||||
|
// 226 -> E2, FFE2 -> APP2 marker, ICC_PROFILE
|
||||||
|
String markerId = "ICC_PROFILE";
|
||||||
|
if (node.getAttribute("MarkerTag").equals("226")
|
||||||
|
&& markerId.equals(new String(data, 0, markerId.length(), StandardCharsets.US_ASCII))) {
|
||||||
|
int offset = markerId.length() + 3; // ICC_PROFILE + null + index + count
|
||||||
|
iccSegments.write(Arrays.copyOfRange(data, offset, data.length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ICC_Profile profile = ICC_Profile.getInstance(iccSegments.toByteArray());
|
||||||
|
assertNotNull(profile); // Assumption, we either have a valid profile, or getInstance blew up...
|
||||||
|
assertEquals(ColorSpace.TYPE_CMYK, profile.getColorSpaceType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTranscodeWithMetadataCMYKtoCMYKNoProfile() throws IOException {
|
||||||
|
ImageWriter writer = createWriter();
|
||||||
|
ImageReader reader = ImageIO.getImageReader(writer);
|
||||||
|
|
||||||
|
// TODO: Add flag to allow removing the ICC profile from image
|
||||||
|
ByteArrayOutputStream stream = transcode(reader, getClassLoaderResource("/jpeg/cmyk-sample-multiple-chunk-icc.jpg"), writer, ColorSpace.TYPE_CMYK, false);
|
||||||
|
|
||||||
|
reader.reset();
|
||||||
|
reader.setInput(new ByteArrayImageInputStream(stream.toByteArray()));
|
||||||
|
|
||||||
|
BufferedImage image = reader.read(0);
|
||||||
|
assertNotNull(image);
|
||||||
|
assertEquals(100, image.getWidth());
|
||||||
|
assertEquals(100, image.getHeight());
|
||||||
|
|
||||||
|
// Test color space type CMYK in standard metadata
|
||||||
|
IIOMetadata metadata = reader.getImageMetadata(0);
|
||||||
|
IIOMetadataNode standard = (IIOMetadataNode) metadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
|
||||||
|
NodeList colorSpaceType = standard.getElementsByTagName("ColorSpaceType");
|
||||||
|
assertEquals(1, colorSpaceType.getLength());
|
||||||
|
assertEquals("CMYK", ((IIOMetadataNode) colorSpaceType.item(0)).getAttribute("name"));
|
||||||
|
|
||||||
|
// Test APP2/ICC_PROFILE segments form native metadata
|
||||||
|
IIOMetadataNode nativeMeta = (IIOMetadataNode) metadata.getAsTree(JPEGImage10Metadata.JAVAX_IMAGEIO_JPEG_IMAGE_1_0);
|
||||||
|
NodeList unknown = nativeMeta.getElementsByTagName("unknown");
|
||||||
|
assertEquals(0, unknown.getLength());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: YCCK
|
// TODO: YCCK
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ 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.stream.URLImageInputStreamSpi;
|
import com.twelvemonkeys.imageio.stream.URLImageInputStreamSpi;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.internal.matchers.LessOrEqual;
|
import org.mockito.internal.matchers.LessOrEqual;
|
||||||
|
|
||||||
@@ -46,7 +47,9 @@ import java.io.IOException;
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* JPEGSegmentImageInputStreamTest
|
* JPEGSegmentImageInputStreamTest
|
||||||
@@ -225,4 +228,29 @@ public class JPEGSegmentImageInputStreamTest {
|
|||||||
assertEquals(-1, iis.read());
|
assertEquals(-1, iis.read());
|
||||||
assertEquals(0x2012, iis.getStreamPosition());
|
assertEquals(0x2012, iis.getStreamPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test(timeout = 1000L)
|
||||||
|
public void testInfiniteLoopCorrupt() throws IOException {
|
||||||
|
try (ImageInputStream stream = new JPEGSegmentImageInputStream(ImageIO.createImageInputStream(getClassLoaderResource("/broken-jpeg/110115680-6d6dce80-7d84-11eb-99df-4cb21df3b09f.jpeg")))) {
|
||||||
|
long length = 0;
|
||||||
|
while (stream.read() != -1) {
|
||||||
|
length++;
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(25504L, length); // Sanity check: same as file size, except..?
|
||||||
|
}
|
||||||
|
|
||||||
|
try (ImageInputStream stream = new JPEGSegmentImageInputStream(ImageIO.createImageInputStream(getClassLoaderResource("/broken-jpeg/110115680-6d6dce80-7d84-11eb-99df-4cb21df3b09f.jpeg")))) {
|
||||||
|
long length = 0;
|
||||||
|
byte[] buffer = new byte[1024];
|
||||||
|
int read;
|
||||||
|
while ((read = stream.read(buffer)) != -1) {
|
||||||
|
length += read;
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(25504L, length); // Sanity check: same as file size, except..?
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
|
After Width: | Height: | Size: 39 KiB |
@@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2010 Dave Perrett, http://recursive-design.com/
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
After Width: | Height: | Size: 342 KiB |
|
After Width: | Height: | Size: 339 KiB |
|
After Width: | Height: | Size: 341 KiB |
|
After Width: | Height: | Size: 341 KiB |