mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2026-05-01 00:00:02 -04:00
Compare commits
99 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b19e45a911 | |||
| a5b6cf898d | |||
| ce597c437d | |||
| fa4b3787d0 | |||
| 3c18e8a510 | |||
| 206481038e | |||
| cff4d88991 | |||
| 8ea8e061a9 | |||
| 101ad18f71 | |||
| 08b441a17e | |||
| b6c76d8566 | |||
| 3f74b2ddf3 | |||
| 46b48f32c3 | |||
| a07d0285fe | |||
| 98de4ad4ec | |||
| aa82612765 | |||
| 9213da3184 | |||
| a5e2226a5a | |||
| 773bedccca | |||
| 6bcc17a020 | |||
| 37d1da9b9d | |||
| 8cf1405dfc | |||
| 8c37d19928 | |||
| 87cd506fdd | |||
| e0c7edebbd | |||
| 5d13bd653f | |||
| 2d974874a9 | |||
| f625622b10 | |||
| dbdd7ae3f1 | |||
| 73883ebf99 | |||
| 970b238066 | |||
| 6cb8ac4b68 | |||
| 1a2a4edfe8 | |||
| a12a1f73b5 | |||
| 46bfdd93d8 | |||
| 447ef6b8eb | |||
| c19b6ede0a | |||
| 401c6355a1 | |||
| be0cf16124 | |||
| 47b0cd6e9a | |||
| b52ab149b3 | |||
| 900c26a5ac | |||
| 7233c593ac | |||
| 8159ba1245 | |||
| 92581a077b | |||
| f87b4d6748 | |||
| 0495f6e266 | |||
| bc7c8ba20c | |||
| 0c270f8343 | |||
| e1db332dca | |||
| 016977e382 | |||
| 134eecc59f | |||
| 16c78052ee | |||
| b51e8ccf6e | |||
| 76a9ff1122 | |||
| e9996f096f | |||
| 93d42e1c24 | |||
| 5824167600 | |||
| 126956ebd0 | |||
| d54ceba3ff | |||
| 11ee7e5e23 | |||
| 954dffd213 | |||
| b7b2a61c93 | |||
| 3cf6a4b836 | |||
| a93be99933 | |||
| b19bd1441f | |||
| 482af60534 | |||
| f55a6d30dd | |||
| e5f6227479 | |||
| 01d6fc8b49 | |||
| f133ea7d61 | |||
| 3d5cf0eecd | |||
| 975e23c28f | |||
| be60f307f7 | |||
| 3e783fba92 | |||
| 35ffe29e03 | |||
| 55155aa61c | |||
| 9e9decd5dd | |||
| 3c0b78549e | |||
| 46db5a2fbf | |||
| f6a9477279 | |||
| b7192ae857 | |||
| c0b2769e3b | |||
| 6c27ec6b30 | |||
| 0c90196357 | |||
| 48f82a159f | |||
| 7105738811 | |||
| 10aa4ba41e | |||
| 6fb06da4d7 | |||
| a963e1c355 | |||
| 966a9da45d | |||
| 319b2c4e18 | |||
| e9bf7d080c | |||
| fb3691e2ee | |||
| 25f9cc5c55 | |||
| 94777ddc96 | |||
| a4c12d0d64 | |||
| 08a69886b1 | |||
| ab85ff0ec8 |
@@ -7,14 +7,14 @@ assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem or use case is.
|
||||
**Is your feature request related to a use case or a problem you are working on? Please describe.**
|
||||
A clear and concise description of what the problem or use case is. Understanding the rationale is key, to be able to implemeent the right solution.
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
A clear and concise description of any alternative solutions or features you've already considered, and why they won't work.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here, like links to specifications or sample files.
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
name: CI
|
||||
|
||||
on: [ push, pull_request ]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Test OpenJDK ${{ matrix.java }} on ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ ubuntu-latest, windows-latest, macos-latest ]
|
||||
java: [ 8, 11, 17 ]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-java@v2
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: ${{ matrix.java }}
|
||||
java-package: jdk
|
||||
cache: 'maven'
|
||||
- name: Run Tests
|
||||
run: mvn test
|
||||
- name: Publish Test Report
|
||||
uses: mikepenz/action-junit-report@v2
|
||||
if: ${{ !cancelled() }}
|
||||
with:
|
||||
report_paths: "**/target/surefire-reports/TEST*.xml"
|
||||
check_name: Unit Test Results for OpenJDK ${{ matrix.java }} on ${{ matrix.os }}
|
||||
|
||||
test_oracle:
|
||||
name: Test Oracle JDK 8 with KCMS=${{ matrix.kcms }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
kcms: [ true, false ]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: |
|
||||
download_url="https://javadl.oracle.com/webapps/download/AutoDL?BundleId=245038_d3c52aa6bfa54d3ca74e617f18309292"
|
||||
wget -O $RUNNER_TEMP/java_package.tar.gz $download_url
|
||||
- uses: actions/setup-java@v2
|
||||
with:
|
||||
distribution: 'jdkfile'
|
||||
jdkFile: ${{ runner.temp }}/java_package.tar.gz
|
||||
java-version: '8'
|
||||
cache: 'maven'
|
||||
- name: Set MAVEN_OPTS
|
||||
if: ${{ matrix.kcms }}
|
||||
run: |
|
||||
echo "MAVEN_OPTS=-Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider" >> $GITHUB_ENV
|
||||
- name: Display Java version
|
||||
run: java -version
|
||||
- name: Run Tests
|
||||
run: mvn test
|
||||
- name: Publish Test Report
|
||||
uses: mikepenz/action-junit-report@v2
|
||||
if: ${{ !cancelled() }}
|
||||
with:
|
||||
report_paths: "**/target/surefire-reports/TEST*.xml"
|
||||
check_name: Unit Test Results for Oracle JDK 8 with KCMS=${{ matrix.kcms }}
|
||||
|
||||
release:
|
||||
name: Deploy
|
||||
needs: [ test, test_oracle ]
|
||||
if: github.ref == 'refs/heads/master' # only perform on latest master
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Maven Central
|
||||
uses: actions/setup-java@v2
|
||||
with: # running setup-java again overwrites the settings.xml
|
||||
distribution: 'temurin'
|
||||
java-version: '8'
|
||||
java-package: jdk
|
||||
server-id: ossrh # Value of the distributionManagement/repository/id field of the pom.xml
|
||||
server-username: MAVEN_CENTRAL_USERNAME # env variable for username in deploy (1)
|
||||
server-password: MAVEN_CENTRAL_PASSWORD # env variable for token in deploy (2)
|
||||
gpg-private-key: ${{ secrets.GPG_KEY }} # Value of the GPG private key to import
|
||||
gpg-passphrase: MAVEN_CENTRAL_GPG_PASSPHRASE # env variable for GPG private key passphrase (3)
|
||||
- name: Get Project Version
|
||||
run: |
|
||||
echo "PROJECT_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)" >> $GITHUB_ENV
|
||||
- name: Publish to Maven Central
|
||||
if: ${{ endsWith(env.PROJECT_VERSION, '-SNAPSHOT') }}
|
||||
run: mvn deploy -P release -DskipTests
|
||||
env:
|
||||
MAVEN_CENTRAL_USERNAME: ${{ secrets.SONATYPE_USERNAME }} # must be the same env variable name as (1)
|
||||
MAVEN_CENTRAL_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} # must be the same env variable name as (2)
|
||||
MAVEN_CENTRAL_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} # must be the same env variable name as (3)
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
dist: trusty
|
||||
language: java
|
||||
jdk:
|
||||
- oraclejdk8 # LTS until Mar 2022
|
||||
- oraclejdk11 # LTS until Sep 2023
|
||||
- oraclejdk15 # out of support
|
||||
- oraclejdk16 # out of support
|
||||
- oraclejdk17 # LTS until Sep 2026
|
||||
jobs:
|
||||
include:
|
||||
# Extra job, testing legacy CMM option
|
||||
- jdk: oraclejdk8
|
||||
env: MAVEN_OPTS=-Dsun.java2d.cmm=sun.java2d.cmm.kcms.KcmsServiceProvider
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.m2
|
||||
@@ -1,5 +1,6 @@
|
||||
[](https://travis-ci.com/github/haraldk/TwelveMonkeys)
|
||||
[](https://maven-badges.herokuapp.com/maven-central/com.twelvemonkeys.imageio/imageio)
|
||||
[](https://github.com/haraldk/TwelveMonkeys/actions/workflows/ci.yml)
|
||||
[](https://search.maven.org/search?q=g:com.twelvemonkeys.imageio)
|
||||
[](https://oss.sonatype.org/content/repositories/snapshots/com/twelvemonkeys/)
|
||||
[](https://stackoverflow.com/questions/tagged/twelvemonkeys)
|
||||
[](https://paypal.me/haraldk76/100)
|
||||
|
||||
@@ -16,36 +17,36 @@ As there is lots of legacy data out there, we see the need for open implementati
|
||||
|
||||
## File formats supported
|
||||
|
||||
| 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](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/bmp_metadata.html) & [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| | 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](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| [ICNS](https://github.com/haraldk/TwelveMonkeys/wiki/ICNS-Plugin) | ICNS | Apple Icon Image | âś” | âś” | - |
|
||||
| [IFF](https://github.com/haraldk/TwelveMonkeys/wiki/IFF-Plugin) | IFF | Commodore Amiga/Electronic Arts Interchange File Format | âś” | âś” | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| [JPEG](https://github.com/haraldk/TwelveMonkeys/wiki/JPEG-Plugin) | **JPEG** | Joint Photographers Expert Group | âś” | âś” | [Native](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/jpeg_metadata.html#image) & [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| | JPEG Lossless | | âś” | - | [Native](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/jpeg_metadata.html#image) & [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| [PCX](https://github.com/haraldk/TwelveMonkeys/wiki/PCX-Plugin) | PCX | ZSoft Paintbrush Format | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| | DCX | Multi-page PCX fax document | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| [PICT](https://github.com/haraldk/TwelveMonkeys/wiki/PICT-Plugin) | PICT | Apple QuickTime Picture Format | âś” | âś” | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| | PNTG | Apple MacPaint Picture Format | âś” | | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| [PNM](https://github.com/haraldk/TwelveMonkeys/wiki/PNM-Plugin) | PAM | NetPBM Portable Any Map | âś” | âś” | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| | PBM | NetPBM Portable Bit Map | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| | PGM | NetPBM Portable Grey Map | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| | PPM | NetPBM Portable Pix Map | âś” | âś” | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| | PFM | Portable Float Map | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| [PSD](https://github.com/haraldk/TwelveMonkeys/wiki/PSD-Plugin) | **PSD** | Adobe Photoshop Document | âś” | - | Native & [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| | PSB | Adobe Photoshop Large Document | âś” | - | Native & [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| [SGI](https://github.com/haraldk/TwelveMonkeys/wiki/SGI-Plugin) | SGI | Silicon Graphics Image Format | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| [TGA](https://github.com/haraldk/TwelveMonkeys/wiki/TGA-Plugin) | TGA | Truevision TGA Image Format | âś” | âś” | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
|ThumbsDB| Thumbs.db| MS Windows Thumbs DB | âś” | - | - | OLE2 Compound Document based format only
|
||||
| [TIFF](https://github.com/haraldk/TwelveMonkeys/wiki/TIFF-Plugin) | **TIFF** | Aldus/Adobe Tagged Image File Format | âś” | âś” | [Native](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/tiff_metadata.html#ImageMetadata) & [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| | BigTIFF | | âś” | - | [Native](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/tiff_metadata.html#ImageMetadata) & [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| [WebP](https://github.com/haraldk/TwelveMonkeys/wiki/WebP-Plugin) | **WebP** | Google WebP Format | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| XWD | XWD | X11 Window Dump Format | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| Plugin | Format | Description | R | W | 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](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/bmp_metadata.html), [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| | 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](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| [ICNS](https://github.com/haraldk/TwelveMonkeys/wiki/ICNS-Plugin) | ICNS | Apple Icon Image | âś” | âś” | - |
|
||||
| [IFF](https://github.com/haraldk/TwelveMonkeys/wiki/IFF-Plugin) | IFF | Commodore Amiga/Electronic Arts Interchange File Format | âś” | âś” | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| [JPEG](https://github.com/haraldk/TwelveMonkeys/wiki/JPEG-Plugin) | **JPEG** | Joint Photographers Expert Group | âś” | âś” | [Native](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/jpeg_metadata.html#image), [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| | JPEG Lossless | | âś” | - | [Native](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/jpeg_metadata.html#image), [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| [PCX](https://github.com/haraldk/TwelveMonkeys/wiki/PCX-Plugin) | PCX | ZSoft Paintbrush Format | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| | DCX | Multi-page PCX fax document | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| [PICT](https://github.com/haraldk/TwelveMonkeys/wiki/PICT-Plugin) | PICT | Apple QuickTime Picture Format | âś” | âś” | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| | PNTG | Apple MacPaint Picture Format | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| [PNM](https://github.com/haraldk/TwelveMonkeys/wiki/PNM-Plugin) | PAM | NetPBM Portable Any Map | âś” | âś” | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| | PBM | NetPBM Portable Bit Map | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| | PGM | NetPBM Portable Grey Map | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| | PPM | NetPBM Portable Pix Map | âś” | âś” | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| | PFM | Portable Float Map | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| [PSD](https://github.com/haraldk/TwelveMonkeys/wiki/PSD-Plugin) | **PSD** | Adobe Photoshop Document | âś” | (âś”) | Native, [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| | PSB | Adobe Photoshop Large Document | âś” | - | Native, [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| [SGI](https://github.com/haraldk/TwelveMonkeys/wiki/SGI-Plugin) | SGI | Silicon Graphics Image Format | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| [TGA](https://github.com/haraldk/TwelveMonkeys/wiki/TGA-Plugin) | TGA | Truevision TGA Image Format | âś” | âś” | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
|ThumbsDB| Thumbs.db| MS Windows Thumbs DB | âś” | - | - | OLE2 Compound Document based format only |
|
||||
| [TIFF](https://github.com/haraldk/TwelveMonkeys/wiki/TIFF-Plugin) | **TIFF** | Aldus/Adobe Tagged Image File Format | âś” | âś” | [Native](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/tiff_metadata.html#ImageMetadata), [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| | BigTIFF | | âś” | âś” | [Native](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/tiff_metadata.html#ImageMetadata), [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| [WebP](https://github.com/haraldk/TwelveMonkeys/wiki/WebP-Plugin) | **WebP** | Google WebP Format | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
| XWD | XWD | X11 Window Dump Format | âś” | - | [Standard](https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html) |
|
||||
|
||||
|
||||
**Important note on using Batik:** *Please read [The Apache™ XML Graphics Project - Security](https://xmlgraphics.apache.org/security.html),
|
||||
@@ -271,12 +272,12 @@ To depend on the JPEG and TIFF plugin using Maven, add the following to your POM
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio-jpeg</artifactId>
|
||||
<version>3.7.0</version>
|
||||
<version>3.8.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio-tiff</artifactId>
|
||||
<version>3.7.0</version>
|
||||
<version>3.8.1</version>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
@@ -286,7 +287,17 @@ To depend on the JPEG and TIFF plugin using Maven, add the following to your POM
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.servlet</groupId>
|
||||
<artifactId>servlet</artifactId>
|
||||
<version>3.7.0</version>
|
||||
<version>3.8.1</version>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
Or Jakarta version, for Servlet API 5.0
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.servlet</groupId>
|
||||
<artifactId>servlet</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<classifier>jakarta</classifier>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
```
|
||||
@@ -295,13 +306,13 @@ To depend on the JPEG and TIFF plugin using Maven, add the following to your POM
|
||||
|
||||
To depend on the JPEG and TIFF plugin in your IDE or program, add all of the following JARs to your class path:
|
||||
|
||||
twelvemonkeys-common-lang-3.7.0.jar
|
||||
twelvemonkeys-common-io-3.7.0.jar
|
||||
twelvemonkeys-common-image-3.7.0.jar
|
||||
twelvemonkeys-imageio-core-3.7.0.jar
|
||||
twelvemonkeys-imageio-metadata-3.7.0.jar
|
||||
twelvemonkeys-imageio-jpeg-3.7.0.jar
|
||||
twelvemonkeys-imageio-tiff-3.7.0.jar
|
||||
twelvemonkeys-common-lang-3.8.1.jar
|
||||
twelvemonkeys-common-io-3.8.1.jar
|
||||
twelvemonkeys-common-image-3.8.1.jar
|
||||
twelvemonkeys-imageio-core-3.8.1.jar
|
||||
twelvemonkeys-imageio-metadata-3.8.1.jar
|
||||
twelvemonkeys-imageio-jpeg-3.8.1.jar
|
||||
twelvemonkeys-imageio-tiff-3.8.1.jar
|
||||
|
||||
#### Deploying the plugins in a web app
|
||||
|
||||
@@ -367,44 +378,44 @@ Other "fat" JAR bundlers will probably have similar mechanisms to merge entries
|
||||
|
||||
### Links to prebuilt binaries
|
||||
|
||||
##### Latest version (3.7.0)
|
||||
##### Latest version (3.8.1)
|
||||
|
||||
Requires Java 7 or later.
|
||||
|
||||
Common dependencies
|
||||
* [common-lang-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-lang/3.7.0/common-lang-3.7.0.jar)
|
||||
* [common-io-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-io/3.7.0/common-io-3.7.0.jar)
|
||||
* [common-image-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-image/3.7.0/common-image-3.7.0.jar)
|
||||
* [common-lang-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-lang/3.8.1/common-lang-3.8.1.jar)
|
||||
* [common-io-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-io/3.8.1/common-io-3.8.1.jar)
|
||||
* [common-image-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-image/3.8.1/common-image-3.8.1.jar)
|
||||
|
||||
ImageIO dependencies
|
||||
* [imageio-core-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-core/3.7.0/imageio-core-3.7.0.jar)
|
||||
* [imageio-metadata-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-metadata/3.7.0/imageio-metadata-3.7.0.jar)
|
||||
* [imageio-core-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-core/3.8.1/imageio-core-3.8.1.jar)
|
||||
* [imageio-metadata-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-metadata/3.8.1/imageio-metadata-3.8.1.jar)
|
||||
|
||||
ImageIO plugins
|
||||
* [imageio-bmp-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-bmp/3.7.0/imageio-bmp-3.7.0.jar)
|
||||
* [imageio-hdr-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-hdr/3.7.0/imageio-hdr-3.7.0.jar)
|
||||
* [imageio-icns-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-icns/3.7.0/imageio-icns-3.7.0.jar)
|
||||
* [imageio-iff-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-iff/3.7.0/imageio-iff-3.7.0.jar)
|
||||
* [imageio-jpeg-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jpeg/3.7.0/imageio-jpeg-3.7.0.jar)
|
||||
* [imageio-pcx-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pcx/3.7.0/imageio-pcx-3.7.0.jar)
|
||||
* [imageio-pict-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pict/3.7.0/imageio-pict-3.7.0.jar)
|
||||
* [imageio-pnm-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pnm/3.7.0/imageio-pnm-3.7.0.jar)
|
||||
* [imageio-psd-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-psd/3.7.0/imageio-psd-3.7.0.jar)
|
||||
* [imageio-sgi-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-sgi/3.7.0/imageio-sgi-3.7.0.jar)
|
||||
* [imageio-tga-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tga/3.7.0/imageio-tga-3.7.0.jar)
|
||||
* [imageio-thumbsdb-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-thumbsdb/3.7.0/imageio-thumbsdb-3.7.0.jar)
|
||||
* [imageio-tiff-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tiff/3.7.0/imageio-tiff-3.7.0.jar)
|
||||
* [imageio-webp-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-webp/3.7.0/imageio-webp-3.7.0.jar)
|
||||
* [imageio-xwd-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-xwd/3.7.0/imageio-xwd-3.7.0.jar)
|
||||
* [imageio-bmp-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-bmp/3.8.1/imageio-bmp-3.8.1.jar)
|
||||
* [imageio-hdr-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-hdr/3.8.1/imageio-hdr-3.8.1.jar)
|
||||
* [imageio-icns-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-icns/3.8.1/imageio-icns-3.8.1.jar)
|
||||
* [imageio-iff-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-iff/3.8.1/imageio-iff-3.8.1.jar)
|
||||
* [imageio-jpeg-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jpeg/3.8.1/imageio-jpeg-3.8.1.jar)
|
||||
* [imageio-pcx-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pcx/3.8.1/imageio-pcx-3.8.1.jar)
|
||||
* [imageio-pict-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pict/3.8.1/imageio-pict-3.8.1.jar)
|
||||
* [imageio-pnm-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pnm/3.8.1/imageio-pnm-3.8.1.jar)
|
||||
* [imageio-psd-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-psd/3.8.1/imageio-psd-3.8.1.jar)
|
||||
* [imageio-sgi-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-sgi/3.8.1/imageio-sgi-3.8.1.jar)
|
||||
* [imageio-tga-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tga/3.8.1/imageio-tga-3.8.1.jar)
|
||||
* [imageio-thumbsdb-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-thumbsdb/3.8.1/imageio-thumbsdb-3.8.1.jar)
|
||||
* [imageio-tiff-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tiff/3.8.1/imageio-tiff-3.8.1.jar)
|
||||
* [imageio-webp-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-webp/3.8.1/imageio-webp-3.8.1.jar)
|
||||
* [imageio-xwd-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-xwd/3.8.1/imageio-xwd-3.8.1.jar)
|
||||
|
||||
ImageIO plugins requiring 3rd party libs
|
||||
* [imageio-batik-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-batik/3.7.0/imageio-batik-3.7.0.jar)
|
||||
* [imageio-batik-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-batik/3.8.1/imageio-batik-3.8.1.jar)
|
||||
|
||||
Photoshop Path support for ImageIO
|
||||
* [imageio-clippath-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-clippath/3.7.0/imageio-clippath-3.7.0.jar)
|
||||
* [imageio-clippath-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-clippath/3.8.1/imageio-clippath-3.8.1.jar)
|
||||
|
||||
Servlet support
|
||||
* [servlet-3.7.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/servlet/servlet/3.7.0/servlet-3.7.0.jar)
|
||||
* [servlet-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/servlet/servlet/3.8.1/servlet-3.8.1.jar)
|
||||
|
||||
##### Old version (3.0.x)
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys</groupId>
|
||||
<artifactId>twelvemonkeys</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<version>3.8.3</version>
|
||||
</parent>
|
||||
|
||||
<groupId>com.twelvemonkeys.bom</groupId>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<version>3.8.3</version>
|
||||
</parent>
|
||||
<artifactId>common-image</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
@@ -31,7 +31,7 @@
|
||||
<dependency>
|
||||
<groupId>jmagick</groupId>
|
||||
<artifactId>jmagick</artifactId>
|
||||
<version>6.2.4</version>
|
||||
<version>6.6.9</version>
|
||||
<optional>true</optional>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<version>3.8.3</version>
|
||||
</parent>
|
||||
<artifactId>common-io</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
@@ -34,6 +34,7 @@ import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* An unsynchronized {@code ByteArrayOutputStream} implementation. This version
|
||||
@@ -42,11 +43,8 @@ import java.io.OutputStream;
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: FastByteArrayOutputStream.java#2 $
|
||||
*/
|
||||
// TODO: Performance test of a stream impl that uses list of fixed size blocks, rather than contiguous block
|
||||
// TODO: Performance test of a stream impl that uses list of fixed size blocks, rather than contiguous block
|
||||
public final class FastByteArrayOutputStream extends ByteArrayOutputStream {
|
||||
/** Max grow size (unless if writing more than this amount of bytes) */
|
||||
protected int maxGrowSize = 1024 * 1024; // 1 MB
|
||||
|
||||
/**
|
||||
* Creates a {@code ByteArrayOutputStream} with the given initial buffer
|
||||
* size.
|
||||
@@ -97,10 +95,8 @@ public final class FastByteArrayOutputStream extends ByteArrayOutputStream {
|
||||
|
||||
private void growIfNeeded(int pNewCount) {
|
||||
if (pNewCount > buf.length) {
|
||||
int newSize = Math.max(Math.min(buf.length << 1, buf.length + maxGrowSize), pNewCount);
|
||||
byte[] newBuf = new byte[newSize];
|
||||
System.arraycopy(buf, 0, newBuf, 0, count);
|
||||
buf = newBuf;
|
||||
int newSize = Math.max(buf.length << 1, pNewCount);
|
||||
buf = Arrays.copyOf(buf, newSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,10 +109,7 @@ public final class FastByteArrayOutputStream extends ByteArrayOutputStream {
|
||||
// Non-synchronized version of toByteArray
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
byte[] newBuf = new byte[count];
|
||||
System.arraycopy(buf, 0, newBuf, 0, count);
|
||||
|
||||
return newBuf;
|
||||
return Arrays.copyOf(buf, count);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -45,39 +45,39 @@ import java.nio.ByteBuffer;
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/DecoderStream.java#2 $
|
||||
*/
|
||||
public final class DecoderStream extends FilterInputStream {
|
||||
protected final ByteBuffer buffer;
|
||||
protected final Decoder decoder;
|
||||
private final ByteBuffer buffer;
|
||||
private final Decoder decoder;
|
||||
|
||||
/**
|
||||
* Creates a new decoder stream and chains it to the
|
||||
* input stream specified by the {@code pStream} argument.
|
||||
* input stream specified by the {@code stream} argument.
|
||||
* The stream will use a default decode buffer size.
|
||||
*
|
||||
* @param pStream the underlying input stream.
|
||||
* @param pDecoder the decoder that will be used to decode the underlying stream
|
||||
* @param stream the underlying input stream.
|
||||
* @param decoder the decoder that will be used to decode the underlying stream
|
||||
*
|
||||
* @see java.io.FilterInputStream#in
|
||||
*/
|
||||
public DecoderStream(final InputStream pStream, final Decoder pDecoder) {
|
||||
public DecoderStream(final InputStream stream, final Decoder decoder) {
|
||||
// TODO: Let the decoder decide preferred buffer size
|
||||
this(pStream, pDecoder, 1024);
|
||||
this(stream, decoder, 1024);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new decoder stream and chains it to the
|
||||
* input stream specified by the {@code pStream} argument.
|
||||
* input stream specified by the {@code stream} argument.
|
||||
*
|
||||
* @param pStream the underlying input stream.
|
||||
* @param pDecoder the decoder that will be used to decode the underlying stream
|
||||
* @param pBufferSize the size of the decode buffer
|
||||
* @param stream the underlying input stream.
|
||||
* @param decoder the decoder that will be used to decode the underlying stream
|
||||
* @param bufferSize the size of the decode buffer
|
||||
*
|
||||
* @see java.io.FilterInputStream#in
|
||||
*/
|
||||
public DecoderStream(final InputStream pStream, final Decoder pDecoder, final int pBufferSize) {
|
||||
super(pStream);
|
||||
public DecoderStream(final InputStream stream, final Decoder decoder, final int bufferSize) {
|
||||
super(stream);
|
||||
|
||||
decoder = pDecoder;
|
||||
buffer = ByteBuffer.allocate(pBufferSize);
|
||||
this.decoder = decoder;
|
||||
buffer = ByteBuffer.allocate(bufferSize);
|
||||
buffer.flip();
|
||||
}
|
||||
|
||||
@@ -95,15 +95,15 @@ public final class DecoderStream extends FilterInputStream {
|
||||
return buffer.get() & 0xff;
|
||||
}
|
||||
|
||||
public int read(final byte pBytes[], final int pOffset, final int pLength) throws IOException {
|
||||
if (pBytes == null) {
|
||||
public int read(final byte[] bytes, final int offset, final int length) throws IOException {
|
||||
if (bytes == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
else if ((pOffset < 0) || (pOffset > pBytes.length) || (pLength < 0) ||
|
||||
((pOffset + pLength) > pBytes.length) || ((pOffset + pLength) < 0)) {
|
||||
throw new IndexOutOfBoundsException("bytes.length=" + pBytes.length + " offset=" + pOffset + " length=" + pLength);
|
||||
else if ((offset < 0) || (offset > bytes.length) || (length < 0) ||
|
||||
((offset + length) > bytes.length) || ((offset + length) < 0)) {
|
||||
throw new IndexOutOfBoundsException("bytes.length=" + bytes.length + " offset=" + offset + " length=" + length);
|
||||
}
|
||||
else if (pLength == 0) {
|
||||
else if (length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -114,11 +114,11 @@ public final class DecoderStream extends FilterInputStream {
|
||||
}
|
||||
}
|
||||
|
||||
// Read until we have read pLength bytes, or have reached EOF
|
||||
// Read until we have read length bytes, or have reached EOF
|
||||
int count = 0;
|
||||
int off = pOffset;
|
||||
int off = offset;
|
||||
|
||||
while (pLength > count) {
|
||||
while (length > count) {
|
||||
if (!buffer.hasRemaining()) {
|
||||
if (fill() < 0) {
|
||||
break;
|
||||
@@ -126,8 +126,8 @@ public final class DecoderStream extends FilterInputStream {
|
||||
}
|
||||
|
||||
// Copy as many bytes as possible
|
||||
int dstLen = Math.min(pLength - count, buffer.remaining());
|
||||
buffer.get(pBytes, off, dstLen);
|
||||
int dstLen = Math.min(length - count, buffer.remaining());
|
||||
buffer.get(bytes, off, dstLen);
|
||||
|
||||
// Update offset (rest)
|
||||
off += dstLen;
|
||||
@@ -139,7 +139,7 @@ public final class DecoderStream extends FilterInputStream {
|
||||
return count;
|
||||
}
|
||||
|
||||
public long skip(final long pLength) throws IOException {
|
||||
public long skip(final long length) throws IOException {
|
||||
// End of file?
|
||||
if (!buffer.hasRemaining()) {
|
||||
if (fill() < 0) {
|
||||
@@ -147,10 +147,10 @@ public final class DecoderStream extends FilterInputStream {
|
||||
}
|
||||
}
|
||||
|
||||
// Skip until we have skipped pLength bytes, or have reached EOF
|
||||
// Skip until we have skipped length bytes, or have reached EOF
|
||||
long total = 0;
|
||||
|
||||
while (total < pLength) {
|
||||
while (total < length) {
|
||||
if (!buffer.hasRemaining()) {
|
||||
if (fill() < 0) {
|
||||
break;
|
||||
@@ -158,7 +158,7 @@ public final class DecoderStream extends FilterInputStream {
|
||||
}
|
||||
|
||||
// NOTE: Skipped can never be more than avail, which is an int, so the cast is safe
|
||||
int skipped = (int) Math.min(pLength - total, buffer.remaining());
|
||||
int skipped = (int) Math.min(length - total, buffer.remaining());
|
||||
buffer.position(buffer.position() + skipped);
|
||||
total += skipped;
|
||||
}
|
||||
@@ -174,7 +174,7 @@ public final class DecoderStream extends FilterInputStream {
|
||||
*
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
protected int fill() throws IOException {
|
||||
private int fill() throws IOException {
|
||||
buffer.clear();
|
||||
int read = decoder.decode(in, buffer);
|
||||
|
||||
|
||||
@@ -45,41 +45,39 @@ import java.nio.ByteBuffer;
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/io/enc/EncoderStream.java#2 $
|
||||
*/
|
||||
public final class EncoderStream extends FilterOutputStream {
|
||||
// TODO: This class need a test case ASAP!!!
|
||||
|
||||
protected final Encoder encoder;
|
||||
private final Encoder encoder;
|
||||
private final boolean flushOnWrite;
|
||||
|
||||
protected final ByteBuffer buffer;
|
||||
private final ByteBuffer buffer;
|
||||
|
||||
/**
|
||||
* Creates an output stream filter built on top of the specified
|
||||
* underlying output stream.
|
||||
*
|
||||
* @param pStream the underlying output stream
|
||||
* @param pEncoder the encoder to use
|
||||
* @param stream the underlying output stream
|
||||
* @param encoder the encoder to use
|
||||
*/
|
||||
public EncoderStream(final OutputStream pStream, final Encoder pEncoder) {
|
||||
this(pStream, pEncoder, false);
|
||||
public EncoderStream(final OutputStream stream, final Encoder encoder) {
|
||||
this(stream, encoder, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an output stream filter built on top of the specified
|
||||
* underlying output stream.
|
||||
*
|
||||
* @param pStream the underlying output stream
|
||||
* @param pEncoder the encoder to use
|
||||
* @param pFlushOnWrite if {@code true}, calls to the byte-array
|
||||
* @param stream the underlying output stream
|
||||
* @param encoder the encoder to use
|
||||
* @param flushOnWrite if {@code true}, calls to the byte-array
|
||||
* {@code write} methods will automatically flush the buffer.
|
||||
*/
|
||||
public EncoderStream(final OutputStream pStream, final Encoder pEncoder, final boolean pFlushOnWrite) {
|
||||
super(pStream);
|
||||
public EncoderStream(final OutputStream stream, final Encoder encoder, final boolean flushOnWrite) {
|
||||
super(stream);
|
||||
|
||||
encoder = pEncoder;
|
||||
flushOnWrite = pFlushOnWrite;
|
||||
this.encoder = encoder;
|
||||
this.flushOnWrite = flushOnWrite;
|
||||
|
||||
buffer = ByteBuffer.allocate(1024);
|
||||
buffer.flip();
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
@@ -104,33 +102,33 @@ public final class EncoderStream extends FilterOutputStream {
|
||||
}
|
||||
}
|
||||
|
||||
public final void write(final byte[] pBytes) throws IOException {
|
||||
write(pBytes, 0, pBytes.length);
|
||||
public void write(final byte[] bytes) throws IOException {
|
||||
write(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
// TODO: Verify that this works for the general case (it probably won't)...
|
||||
// TODO: We might need a way to explicitly flush the encoder, or specify
|
||||
// that the encoder can't buffer. In that case, the encoder should probably
|
||||
// tell the EncoderStream how large buffer it prefers...
|
||||
public void write(final byte[] pBytes, final int pOffset, final int pLength) throws IOException {
|
||||
if (!flushOnWrite && pLength < buffer.remaining()) {
|
||||
// tell the EncoderStream how large buffer it prefers...
|
||||
public void write(final byte[] values, final int offset, final int length) throws IOException {
|
||||
if (!flushOnWrite && length < buffer.remaining()) {
|
||||
// Buffer data
|
||||
buffer.put(pBytes, pOffset, pLength);
|
||||
buffer.put(values, offset, length);
|
||||
}
|
||||
else {
|
||||
// Encode data already in the buffer
|
||||
encodeBuffer();
|
||||
|
||||
// Encode rest without buffering
|
||||
encoder.encode(out, ByteBuffer.wrap(pBytes, pOffset, pLength));
|
||||
encoder.encode(out, ByteBuffer.wrap(values, offset, length));
|
||||
}
|
||||
}
|
||||
|
||||
public void write(final int pByte) throws IOException {
|
||||
public void write(final int value) throws IOException {
|
||||
if (!buffer.hasRemaining()) {
|
||||
encodeBuffer(); // Resets bufferPos to 0
|
||||
}
|
||||
|
||||
buffer.put((byte) pByte);
|
||||
buffer.put((byte) value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.io.enc;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class DecoderStreamTest {
|
||||
|
||||
private final Random rng = new Random(5467809876546L);
|
||||
|
||||
private byte[] createData(final int length) {
|
||||
byte[] data = new byte[length];
|
||||
rng.nextBytes(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDecodeSingleBytes() throws IOException {
|
||||
byte[] data = createData(1327);
|
||||
|
||||
InputStream source = new ByteArrayInputStream(data);
|
||||
try (InputStream stream = new DecoderStream(source, new NullDecoder())) {
|
||||
for (byte datum : data) {
|
||||
int read = stream.read();
|
||||
assertNotEquals(-1, read);
|
||||
assertEquals(datum, (byte) read);
|
||||
}
|
||||
|
||||
assertEquals(-1, stream.read());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDecodeArray() throws IOException {
|
||||
int length = 793;
|
||||
byte[] data = createData(length * 10);
|
||||
|
||||
InputStream source = new ByteArrayInputStream(data);
|
||||
byte[] result = new byte[477];
|
||||
|
||||
try (InputStream stream = new DecoderStream(source, new NullDecoder())) {
|
||||
int dataOffset = 0;
|
||||
while (dataOffset < data.length) {
|
||||
int count = stream.read(result);
|
||||
|
||||
assertFalse(count <= 0);
|
||||
assertArrayEquals(Arrays.copyOfRange(data, dataOffset, dataOffset + count), Arrays.copyOfRange(result, 0, count));
|
||||
|
||||
dataOffset += count;
|
||||
}
|
||||
|
||||
assertEquals(-1, stream.read());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDecodeArrayOffset() throws IOException {
|
||||
int length = 793;
|
||||
byte[] data = createData(length * 10);
|
||||
|
||||
InputStream source = new ByteArrayInputStream(data);
|
||||
byte[] result = new byte[477];
|
||||
|
||||
try (InputStream stream = new DecoderStream(source, new NullDecoder())) {
|
||||
int dataOffset = 0;
|
||||
while (dataOffset < data.length) {
|
||||
int resultOffset = dataOffset % result.length;
|
||||
int count = stream.read(result, resultOffset, result.length - resultOffset);
|
||||
|
||||
assertFalse(count <= 0);
|
||||
assertArrayEquals(Arrays.copyOfRange(data, dataOffset + resultOffset, dataOffset + count), Arrays.copyOfRange(result, resultOffset, count));
|
||||
|
||||
dataOffset += count;
|
||||
}
|
||||
|
||||
assertEquals(-1, stream.read());
|
||||
}
|
||||
}
|
||||
|
||||
private static final class NullDecoder implements Decoder {
|
||||
@Override
|
||||
public int decode(InputStream stream, ByteBuffer buffer) throws IOException {
|
||||
int read = stream.read(buffer.array(), buffer.arrayOffset(), buffer.remaining());
|
||||
|
||||
if (read > 0) {
|
||||
// Set position, should be equivalent to using buffer.put(stream.read()) until EOF or buffer full
|
||||
buffer.position(read);
|
||||
}
|
||||
|
||||
return read;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.io.enc;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
public class EncoderStreamTest {
|
||||
|
||||
private final Random rng = new Random(5467809876546L);
|
||||
|
||||
private byte[] createData(final int length) {
|
||||
byte[] data = new byte[length];
|
||||
rng.nextBytes(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeSingleBytes() throws IOException {
|
||||
byte[] data = createData(1327);
|
||||
|
||||
ByteArrayOutputStream result = new ByteArrayOutputStream();
|
||||
try (OutputStream stream = new EncoderStream(result, new NullEncoder())) {
|
||||
for (byte datum : data) {
|
||||
stream.write(datum);
|
||||
}
|
||||
}
|
||||
|
||||
assertArrayEquals(data, result.toByteArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeArray() throws IOException {
|
||||
byte[] data = createData(1793);
|
||||
|
||||
ByteArrayOutputStream result = new ByteArrayOutputStream();
|
||||
try (OutputStream stream = new EncoderStream(result, new NullEncoder())) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
stream.write(data);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] encoded = result.toByteArray();
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
assertArrayEquals(data, Arrays.copyOfRange(encoded, i * data.length, (i + 1) * data.length));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeArrayOffset() throws IOException {
|
||||
byte[] data = createData(87);
|
||||
|
||||
ByteArrayOutputStream result = new ByteArrayOutputStream();
|
||||
try (OutputStream stream = new EncoderStream(result, new NullEncoder())) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
stream.write(data, 13, 59);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] original = Arrays.copyOfRange(data, 13, 13 + 59);
|
||||
byte[] encoded = result.toByteArray();
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
assertArrayEquals(original, Arrays.copyOfRange(encoded, i * original.length, (i + 1) * original.length));
|
||||
}
|
||||
}
|
||||
|
||||
private static final class NullEncoder implements Encoder {
|
||||
@Override
|
||||
public void encode(OutputStream stream, ByteBuffer buffer) throws IOException {
|
||||
stream.write(buffer.array(), buffer.arrayOffset(), buffer.remaining());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<version>3.8.3</version>
|
||||
</parent>
|
||||
<artifactId>common-lang</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys</groupId>
|
||||
<artifactId>twelvemonkeys</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<version>3.8.3</version>
|
||||
</parent>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys</groupId>
|
||||
<artifactId>twelvemonkeys</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<version>3.8.3</version>
|
||||
</parent>
|
||||
<groupId>com.twelvemonkeys.contrib</groupId>
|
||||
<artifactId>contrib</artifactId>
|
||||
|
||||
@@ -30,9 +30,14 @@ import static com.twelvemonkeys.contrib.tiff.TIFFUtilities.applyOrientation;
|
||||
public class EXIFUtilities {
|
||||
/**
|
||||
* Reads image and metadata, applies Exif orientation to image, and returns everything as an {@code IIOImage}.
|
||||
* The returned {@code IIOImage} will always contain an image and no raster, and
|
||||
* the {@code RenderedImage} may be safely cast to a {@code BufferedImage}.
|
||||
*
|
||||
* If no registered {@code ImageReader} claims to be able to read the input, {@code null} is returned.
|
||||
*
|
||||
* @param input a {@code URL}
|
||||
* @return an {@code IIOImage} containing the correctly oriented image and metadata including rotation info.
|
||||
* @return an {@code IIOImage} containing the correctly oriented image and metadata including rotation info, or
|
||||
* {@code null}.
|
||||
* @throws IOException if an error occurs during reading.
|
||||
*/
|
||||
public static IIOImage readWithOrientation(final URL input) throws IOException {
|
||||
@@ -43,9 +48,14 @@ public class EXIFUtilities {
|
||||
|
||||
/**
|
||||
* Reads image and metadata, applies Exif orientation to image, and returns everything as an {@code IIOImage}.
|
||||
* The returned {@code IIOImage} will always contain an image and no raster, and
|
||||
* the {@code RenderedImage} may be safely cast to a {@code BufferedImage}.
|
||||
*
|
||||
* If no registered {@code ImageReader} claims to be able to read the input, {@code null} is returned.
|
||||
*
|
||||
* @param input an {@code InputStream}
|
||||
* @return an {@code IIOImage} containing the correctly oriented image and metadata including rotation info.
|
||||
* @return an {@code IIOImage} containing the correctly oriented image and metadata including rotation info, or
|
||||
* {@code null}.
|
||||
* @throws IOException if an error occurs during reading.
|
||||
*/
|
||||
public static IIOImage readWithOrientation(final InputStream input) throws IOException {
|
||||
@@ -56,9 +66,14 @@ public class EXIFUtilities {
|
||||
|
||||
/**
|
||||
* Reads image and metadata, applies Exif orientation to image, and returns everything as an {@code IIOImage}.
|
||||
* The returned {@code IIOImage} will always contain an image and no raster, and
|
||||
* the {@code RenderedImage} may be safely cast to a {@code BufferedImage}.
|
||||
*
|
||||
* If no registered {@code ImageReader} claims to be able to read the input, {@code null} is returned.
|
||||
*
|
||||
* @param input a {@code File}
|
||||
* @return an {@code IIOImage} containing the correctly oriented image and metadata including rotation info.
|
||||
* @return an {@code IIOImage} containing the correctly oriented image and metadata including rotation info or
|
||||
* {@code null}.
|
||||
* @throws IOException if an error occurs during reading.
|
||||
*/
|
||||
public static IIOImage readWithOrientation(final File input) throws IOException {
|
||||
@@ -69,9 +84,14 @@ public class EXIFUtilities {
|
||||
|
||||
/**
|
||||
* Reads image and metadata, applies Exif orientation to image, and returns everything as an {@code IIOImage}.
|
||||
* The returned {@code IIOImage} will always contain an image and no raster, and
|
||||
* the {@code RenderedImage} may be safely cast to a {@code BufferedImage}.
|
||||
*
|
||||
* If no registered {@code ImageReader} claims to be able to read the input, {@code null} is returned.
|
||||
*
|
||||
* @param input an {@code ImageInputStream}
|
||||
* @return an {@code IIOImage} containing the correctly oriented image and metadata including rotation info.
|
||||
* @return an {@code IIOImage} containing the correctly oriented image and metadata including rotation info, or
|
||||
* {@code null}.
|
||||
* @throws IOException if an error occurs during reading.
|
||||
*/
|
||||
public static IIOImage readWithOrientation(final ImageInputStream input) throws IOException {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<version>3.8.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-batik</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: Batik Plugin</name>
|
||||
@@ -27,9 +27,9 @@
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<com.twelvemonkeys.imageio.plugins.svg.allowexternalresources>
|
||||
<com.twelvemonkeys.imageio.plugins.svg.allowExternalResources>
|
||||
true
|
||||
</com.twelvemonkeys.imageio.plugins.svg.allowexternalresources>
|
||||
</com.twelvemonkeys.imageio.plugins.svg.allowExternalResources>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
@@ -48,6 +48,13 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.11.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.xmlgraphics</groupId>
|
||||
<artifactId>batik-rasterizer-ext</artifactId>
|
||||
|
||||
+109
-103
@@ -30,21 +30,10 @@
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.svg;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import com.twelvemonkeys.image.ImageUtil;
|
||||
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
|
||||
import org.apache.batik.anim.dom.SVGDOMImplementation;
|
||||
import org.apache.batik.anim.dom.SVGOMDocument;
|
||||
@@ -68,10 +57,19 @@ import org.w3c.dom.DOMImplementation;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.svg.SVGSVGElement;
|
||||
|
||||
import com.twelvemonkeys.image.ImageUtil;
|
||||
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import java.awt.*;
|
||||
import java.awt.geom.*;
|
||||
import java.awt.image.*;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Image reader for SVG document fragments.
|
||||
@@ -79,12 +77,13 @@ import com.twelvemonkeys.lang.StringUtil;
|
||||
* @author Harald Kuhr
|
||||
* @author Inpspired by code from the Batik Team
|
||||
* @version $Id: $
|
||||
* @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 {
|
||||
|
||||
final static boolean DEFAULT_ALLOW_EXTERNAL_RESOURCES =
|
||||
"true".equalsIgnoreCase(System.getProperty("com.twelvemonkeys.imageio.plugins.svg.allowexternalresources"));
|
||||
"true".equalsIgnoreCase(System.getProperty("com.twelvemonkeys.imageio.plugins.svg.allowExternalResources",
|
||||
System.getProperty("com.twelvemonkeys.imageio.plugins.svg.allowexternalresources")));
|
||||
|
||||
private Rasterizer rasterizer;
|
||||
private boolean allowExternalResources = DEFAULT_ALLOW_EXTERNAL_RESOURCES;
|
||||
@@ -150,29 +149,23 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
BufferedImage destination = getDestination(pParam, getImageTypes(pIndex), size.width, size.height);
|
||||
|
||||
// Read in the image, using the Batik Transcoder
|
||||
processImageStarted(pIndex);
|
||||
|
||||
BufferedImage image = rasterizer.getImage();
|
||||
|
||||
Graphics2D g = destination.createGraphics();
|
||||
try {
|
||||
processImageStarted(pIndex);
|
||||
|
||||
BufferedImage image = rasterizer.getImage();
|
||||
|
||||
Graphics2D g = destination.createGraphics();
|
||||
try {
|
||||
g.setComposite(AlphaComposite.Src);
|
||||
g.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
|
||||
g.drawImage(image, 0, 0, null); // TODO: Dest offset?
|
||||
}
|
||||
finally {
|
||||
g.dispose();
|
||||
}
|
||||
|
||||
processImageComplete();
|
||||
|
||||
return destination;
|
||||
g.setComposite(AlphaComposite.Src);
|
||||
g.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
|
||||
g.drawImage(image, 0, 0, null); // TODO: Dest offset?
|
||||
}
|
||||
catch (TranscoderException e) {
|
||||
Throwable cause = unwrapException(e);
|
||||
throw new IIOException(cause.getMessage(), cause);
|
||||
finally {
|
||||
g.dispose();
|
||||
}
|
||||
|
||||
processImageComplete();
|
||||
|
||||
return destination;
|
||||
}
|
||||
|
||||
private static Throwable unwrapException(TranscoderException ex) {
|
||||
@@ -187,11 +180,11 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
|
||||
// Set dimensions
|
||||
Dimension size = pParam.getSourceRenderSize();
|
||||
Dimension origSize = new Dimension(getWidth(0), getHeight(0));
|
||||
Rectangle viewBox = rasterizer.getViewBox();
|
||||
if (size == null) {
|
||||
// SVG is not a pixel based format, but we'll scale it, according to
|
||||
// the subsampling for compatibility
|
||||
size = getSourceRenderSizeFromSubsamping(pParam, origSize);
|
||||
size = getSourceRenderSizeFromSubsamping(pParam, viewBox.getSize());
|
||||
}
|
||||
|
||||
if (size != null) {
|
||||
@@ -211,8 +204,8 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
}
|
||||
else {
|
||||
// Need to resize here...
|
||||
double xScale = size.getWidth() / origSize.getWidth();
|
||||
double yScale = size.getHeight() / origSize.getHeight();
|
||||
double xScale = size.getWidth() / viewBox.getWidth();
|
||||
double yScale = size.getHeight() / viewBox.getHeight();
|
||||
|
||||
hints.put(ImageTranscoder.KEY_WIDTH, (float) (region.getWidth() * xScale));
|
||||
hints.put(ImageTranscoder.KEY_HEIGHT, (float) (region.getHeight() * yScale));
|
||||
@@ -220,7 +213,7 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
}
|
||||
else if (size != null) {
|
||||
// Allow non-uniform scaling
|
||||
hints.put(ImageTranscoder.KEY_AOI, new Rectangle(origSize));
|
||||
hints.put(ImageTranscoder.KEY_AOI, viewBox);
|
||||
}
|
||||
|
||||
// Background color
|
||||
@@ -235,7 +228,7 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
private Dimension getSourceRenderSizeFromSubsamping(ImageReadParam pParam, Dimension pOrigSize) {
|
||||
if (pParam.getSourceXSubsampling() > 1 || pParam.getSourceYSubsampling() > 1) {
|
||||
return new Dimension((int) (pOrigSize.width / (float) pParam.getSourceXSubsampling()),
|
||||
(int) (pOrigSize.height / (float) pParam.getSourceYSubsampling()));
|
||||
(int) (pOrigSize.height / (float) pParam.getSourceYSubsampling()));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -246,22 +239,13 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
|
||||
public int getWidth(int pIndex) throws IOException {
|
||||
checkBounds(pIndex);
|
||||
try {
|
||||
return rasterizer.getDefaultWidth();
|
||||
}
|
||||
catch (TranscoderException e) {
|
||||
throw new IIOException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
return rasterizer.getDefaultWidth();
|
||||
}
|
||||
|
||||
public int getHeight(int pIndex) throws IOException {
|
||||
checkBounds(pIndex);
|
||||
try {
|
||||
return rasterizer.getDefaultHeight();
|
||||
}
|
||||
catch (TranscoderException e) {
|
||||
throw new IIOException(e.getMessage(), e);
|
||||
}
|
||||
return rasterizer.getDefaultHeight();
|
||||
}
|
||||
|
||||
public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) {
|
||||
@@ -275,12 +259,11 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
* and needs major refactoring!
|
||||
* </p>
|
||||
*/
|
||||
private class Rasterizer extends SVGAbstractTranscoder /*ImageTranscoder*/ {
|
||||
|
||||
private class Rasterizer extends SVGAbstractTranscoder {
|
||||
private BufferedImage image;
|
||||
private TranscoderInput transcoderInput;
|
||||
private float defaultWidth;
|
||||
private float defaultHeight;
|
||||
private final Rectangle2D viewBox = new Rectangle2D.Float();
|
||||
private final Dimension defaultSize = new Dimension();
|
||||
private boolean initialized = false;
|
||||
private SVGOMDocument document;
|
||||
private String uri;
|
||||
@@ -341,54 +324,66 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
// ----
|
||||
SVGSVGElement rootElement = svgDoc.getRootElement();
|
||||
|
||||
// get the 'width' and 'height' attributes of the SVG document
|
||||
UnitProcessor.Context uctx
|
||||
= UnitProcessor.createContext(ctx, rootElement);
|
||||
// Get the viewBox
|
||||
String viewBoxStr = rootElement.getAttributeNS(null, SVGConstants.SVG_VIEW_BOX_ATTRIBUTE);
|
||||
if (viewBoxStr.length() != 0) {
|
||||
float[] rect = ViewBox.parseViewBoxAttribute(rootElement, viewBoxStr, null);
|
||||
viewBox.setFrame(rect[0], rect[1], rect[2], rect[3]);
|
||||
}
|
||||
|
||||
// Get the 'width' and 'height' attributes of the SVG document
|
||||
double width = 0;
|
||||
double height = 0;
|
||||
UnitProcessor.Context uctx = UnitProcessor.createContext(ctx, rootElement);
|
||||
String widthStr = rootElement.getAttributeNS(null, SVGConstants.SVG_WIDTH_ATTRIBUTE);
|
||||
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);
|
||||
width = UnitProcessor.svgToUserSpace(widthStr, SVGConstants.SVG_WIDTH_ATTRIBUTE, UnitProcessor.HORIZONTAL_LENGTH, uctx);
|
||||
}
|
||||
if(!StringUtil.isEmpty(heightStr)){
|
||||
defaultHeight = UnitProcessor.svgToUserSpace(heightStr, SVGConstants.SVG_HEIGHT_ATTRIBUTE, UnitProcessor.VERTICAL_LENGTH, uctx);
|
||||
if (!StringUtil.isEmpty(heightStr)) {
|
||||
height = UnitProcessor.svgToUserSpace(heightStr, SVGConstants.SVG_HEIGHT_ATTRIBUTE, UnitProcessor.VERTICAL_LENGTH, uctx);
|
||||
}
|
||||
|
||||
boolean hasWidth = defaultWidth > 0.0;
|
||||
boolean hasHeight = defaultHeight > 0.0;
|
||||
boolean hasWidth = width > 0.0;
|
||||
boolean hasHeight = height > 0.0;
|
||||
|
||||
if (!hasWidth || !hasHeight) {
|
||||
String viewBoxStr = rootElement.getAttributeNS
|
||||
(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 (!viewBox.isEmpty()) {
|
||||
// If one dimension is given, calculate other by aspect ratio in viewBox
|
||||
if (hasWidth) {
|
||||
defaultHeight = defaultWidth * rect[3] / rect[2];
|
||||
height = width * viewBox.getHeight() / viewBox.getWidth();
|
||||
}
|
||||
else if (hasHeight) {
|
||||
defaultWidth = defaultHeight * rect[2] / rect[3];
|
||||
width = height * viewBox.getWidth() / viewBox.getHeight();
|
||||
}
|
||||
else {
|
||||
defaultWidth = rect[2];
|
||||
defaultHeight = rect[3];
|
||||
// ...or use viewBox if no dimension is given
|
||||
width = viewBox.getWidth();
|
||||
height = viewBox.getHeight();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// No viewBox, just assume square size
|
||||
if (hasHeight) {
|
||||
defaultWidth = defaultHeight;
|
||||
width = height;
|
||||
}
|
||||
else if (hasWidth) {
|
||||
defaultHeight = defaultWidth;
|
||||
height = width;
|
||||
}
|
||||
else {
|
||||
// fallback to batik default sizes
|
||||
defaultWidth = 400;
|
||||
defaultHeight = 400;
|
||||
// ...or finally fall back to Batik default sizes
|
||||
width = 400;
|
||||
height = 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We now have a size, in the rare case we don't have a viewBox; set it to this size
|
||||
defaultSize.setSize(width, height);
|
||||
if (viewBox.isEmpty()) {
|
||||
viewBox.setRect(0, 0, width, height);
|
||||
}
|
||||
|
||||
// Hack to work around exception above
|
||||
if (root != null) {
|
||||
gvtRoot = root;
|
||||
@@ -401,7 +396,7 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
ctx = null;
|
||||
}
|
||||
|
||||
private BufferedImage readImage() throws TranscoderException {
|
||||
private BufferedImage readImage() throws IOException {
|
||||
init();
|
||||
|
||||
if (abortRequested()) {
|
||||
@@ -426,7 +421,8 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
}
|
||||
|
||||
if (gvtRoot == null) {
|
||||
throw exception;
|
||||
Throwable cause = unwrapException(exception);
|
||||
throw new IIOException(cause.getMessage(), cause);
|
||||
}
|
||||
}
|
||||
ctx = context;
|
||||
@@ -444,7 +440,7 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
|
||||
|
||||
// ----
|
||||
setImageSize(defaultWidth, defaultHeight);
|
||||
setImageSize(defaultSize.width, defaultSize.height);
|
||||
|
||||
if (abortRequested()) {
|
||||
processReadAborted();
|
||||
@@ -458,18 +454,17 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
|
||||
try {
|
||||
Px = ViewBox.getViewTransform(ref, root, width, height, null);
|
||||
|
||||
}
|
||||
catch (BridgeException ex) {
|
||||
throw new TranscoderException(ex);
|
||||
throw new IIOException(ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
if (Px.isIdentity() && (width != defaultWidth || height != defaultHeight)) {
|
||||
if (Px.isIdentity() && (width != defaultSize.width || height != defaultSize.height)) {
|
||||
// The document has no viewBox, we need to resize it by hand.
|
||||
// we want to keep the document size ratio
|
||||
float xscale, yscale;
|
||||
xscale = width / defaultWidth;
|
||||
yscale = height / defaultHeight;
|
||||
xscale = width / defaultSize.width;
|
||||
yscale = height / defaultSize.height;
|
||||
float scale = Math.min(xscale, yscale);
|
||||
Px = AffineTransform.getScaleInstance(scale, scale);
|
||||
}
|
||||
@@ -519,7 +514,7 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
}
|
||||
}
|
||||
catch (BridgeException ex) {
|
||||
throw new TranscoderException(ex);
|
||||
throw new IIOException(ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
this.root = gvtRoot;
|
||||
@@ -588,7 +583,7 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
return dest;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new TranscoderException(ex.getMessage(), ex);
|
||||
throw new IIOException(ex.getMessage(), ex);
|
||||
}
|
||||
finally {
|
||||
if (context != null) {
|
||||
@@ -597,7 +592,7 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void init() throws TranscoderException {
|
||||
private synchronized void init() throws IIOException {
|
||||
if (!initialized) {
|
||||
if (transcoderInput == null) {
|
||||
throw new IllegalStateException("input == null");
|
||||
@@ -605,11 +600,17 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
|
||||
initialized = true;
|
||||
|
||||
super.transcode(transcoderInput, null);
|
||||
try {
|
||||
super.transcode(transcoderInput, null);
|
||||
}
|
||||
catch (TranscoderException e) {
|
||||
Throwable cause = unwrapException(e);
|
||||
throw new IIOException(cause.getMessage(), cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private BufferedImage getImage() throws TranscoderException {
|
||||
private BufferedImage getImage() throws IOException {
|
||||
if (image == null) {
|
||||
image = readImage();
|
||||
}
|
||||
@@ -617,14 +618,19 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
return image;
|
||||
}
|
||||
|
||||
int getDefaultWidth() throws TranscoderException {
|
||||
int getDefaultWidth() throws IOException {
|
||||
init();
|
||||
return (int) Math.ceil(defaultWidth);
|
||||
return defaultSize.width;
|
||||
}
|
||||
|
||||
int getDefaultHeight() throws TranscoderException {
|
||||
int getDefaultHeight() throws IOException {
|
||||
init();
|
||||
return (int) Math.ceil(defaultHeight);
|
||||
return defaultSize.height;
|
||||
}
|
||||
|
||||
Rectangle getViewBox() throws IOException {
|
||||
init();
|
||||
return viewBox.getBounds();
|
||||
}
|
||||
|
||||
void setInput(final TranscoderInput pInput) {
|
||||
|
||||
+143
-141
@@ -1,141 +1,143 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.wmf;
|
||||
|
||||
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||
import com.twelvemonkeys.imageio.plugins.svg.SVGImageReader;
|
||||
import com.twelvemonkeys.imageio.plugins.svg.SVGReadParam;
|
||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||
import org.apache.batik.transcoder.TranscoderException;
|
||||
import org.apache.batik.transcoder.TranscoderInput;
|
||||
import org.apache.batik.transcoder.TranscoderOutput;
|
||||
import org.apache.batik.transcoder.wmf.tosvg.WMFTranscoder;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* WMFImageReader class description.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: WMFImageReader.java,v 1.0 29.jul.2004 13:00:59 haku Exp $
|
||||
*/
|
||||
// TODO: Probably possible to do less wrapping/unwrapping of data...
|
||||
// TODO: Consider using temp file instead of in-memory stream
|
||||
public final class WMFImageReader extends ImageReaderBase {
|
||||
|
||||
private SVGImageReader reader = null;
|
||||
|
||||
public WMFImageReader(final ImageReaderSpi pProvider) {
|
||||
super(pProvider);
|
||||
}
|
||||
|
||||
protected void resetMembers() {
|
||||
if (reader != null) {
|
||||
reader.dispose();
|
||||
}
|
||||
|
||||
reader = null;
|
||||
}
|
||||
|
||||
public BufferedImage read(int pIndex, ImageReadParam pParam) throws IOException {
|
||||
init();
|
||||
|
||||
processImageStarted(pIndex);
|
||||
|
||||
BufferedImage image = reader.read(pIndex, pParam);
|
||||
if (abortRequested()) {
|
||||
processReadAborted();
|
||||
return image;
|
||||
}
|
||||
processImageProgress(100f);
|
||||
|
||||
processImageComplete();
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
private synchronized void init() throws IOException {
|
||||
// Need the extra test, to avoid throwing an IOException from the Transcoder
|
||||
if (imageInput == null) {
|
||||
throw new IllegalStateException("input == null");
|
||||
}
|
||||
|
||||
if (reader == null) {
|
||||
WMFTranscoder transcoder = new WMFTranscoder();
|
||||
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
Writer writer = new OutputStreamWriter(output, "UTF8");
|
||||
try {
|
||||
TranscoderInput in = new TranscoderInput(IIOUtil.createStreamAdapter(imageInput));
|
||||
TranscoderOutput out = new TranscoderOutput(writer);
|
||||
|
||||
// TODO: Transcodinghints?
|
||||
|
||||
transcoder.transcode(in, out);
|
||||
}
|
||||
catch (TranscoderException e) {
|
||||
throw new IIOException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
reader = new SVGImageReader(getOriginatingProvider());
|
||||
reader.setInput(ImageIO.createImageInputStream(new ByteArrayInputStream(output.toByteArray())));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageReadParam getDefaultReadParam() {
|
||||
return new SVGReadParam();
|
||||
}
|
||||
|
||||
public int getWidth(int pIndex) throws IOException {
|
||||
init();
|
||||
return reader.getWidth(pIndex);
|
||||
}
|
||||
|
||||
public int getHeight(int pIndex) throws IOException {
|
||||
init();
|
||||
return reader.getHeight(pIndex);
|
||||
}
|
||||
|
||||
public Iterator<ImageTypeSpecifier> getImageTypes(final int pImageIndex) throws IOException {
|
||||
init();
|
||||
return reader.getImageTypes(pImageIndex);
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.wmf;
|
||||
|
||||
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||
import com.twelvemonkeys.imageio.plugins.svg.SVGImageReader;
|
||||
import com.twelvemonkeys.imageio.plugins.svg.SVGReadParam;
|
||||
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||
|
||||
import org.apache.batik.transcoder.TranscoderException;
|
||||
import org.apache.batik.transcoder.TranscoderInput;
|
||||
import org.apache.batik.transcoder.TranscoderOutput;
|
||||
import org.apache.batik.transcoder.wmf.tosvg.WMFTranscoder;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import java.awt.image.*;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* WMFImageReader class description.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: WMFImageReader.java,v 1.0 29.jul.2004 13:00:59 haku Exp $
|
||||
*/
|
||||
// TODO: Probably possible to do less wrapping/unwrapping of data...
|
||||
public final class WMFImageReader extends ImageReaderBase {
|
||||
|
||||
private SVGImageReader reader = null;
|
||||
|
||||
public WMFImageReader(final ImageReaderSpi pProvider) {
|
||||
super(pProvider);
|
||||
}
|
||||
|
||||
protected void resetMembers() {
|
||||
if (reader != null) {
|
||||
reader.dispose();
|
||||
}
|
||||
|
||||
reader = null;
|
||||
}
|
||||
|
||||
public BufferedImage read(int pIndex, ImageReadParam pParam) throws IOException {
|
||||
init();
|
||||
|
||||
processImageStarted(pIndex);
|
||||
|
||||
BufferedImage image = reader.read(pIndex, pParam);
|
||||
if (abortRequested()) {
|
||||
processReadAborted();
|
||||
return image;
|
||||
}
|
||||
processImageProgress(100f);
|
||||
|
||||
processImageComplete();
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
private void init() throws IOException {
|
||||
// Need the extra test, to avoid throwing an IOException from the Transcoder
|
||||
if (imageInput == null) {
|
||||
throw new IllegalStateException("input == null");
|
||||
}
|
||||
|
||||
if (reader == null) {
|
||||
WMFTranscoder transcoder = new WMFTranscoder();
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream(8192);
|
||||
|
||||
try (Writer writer = new OutputStreamWriter(output, StandardCharsets.UTF_8)) {
|
||||
TranscoderInput in = new TranscoderInput(IIOUtil.createStreamAdapter(imageInput));
|
||||
TranscoderOutput out = new TranscoderOutput(writer);
|
||||
|
||||
// TODO: Transcodinghints?
|
||||
|
||||
transcoder.transcode(in, out);
|
||||
}
|
||||
catch (TranscoderException e) {
|
||||
throw new IIOException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
reader = new SVGImageReader(getOriginatingProvider());
|
||||
reader.setInput(new ByteArrayImageInputStream(output.toByteArray()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageReadParam getDefaultReadParam() {
|
||||
return new SVGReadParam();
|
||||
}
|
||||
|
||||
public int getWidth(int pIndex) throws IOException {
|
||||
init();
|
||||
return reader.getWidth(pIndex);
|
||||
}
|
||||
|
||||
public int getHeight(int pIndex) throws IOException {
|
||||
init();
|
||||
return reader.getHeight(pIndex);
|
||||
}
|
||||
|
||||
public Iterator<ImageTypeSpecifier> getImageTypes(final int pImageIndex) throws IOException {
|
||||
init();
|
||||
return reader.getImageTypes(pImageIndex);
|
||||
}
|
||||
}
|
||||
|
||||
+72
-5
@@ -43,8 +43,7 @@ import javax.imageio.event.IIOReadWarningListener;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ImagingOpException;
|
||||
import java.awt.image.*;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URISyntaxException;
|
||||
@@ -53,7 +52,10 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
@@ -192,12 +194,12 @@ public class SVGImageReaderTest extends ImageReaderAbstractTest<SVGImageReader>
|
||||
TestData redSquare = new TestData(getClassLoaderResource("/svg/red-square.svg"), dim);
|
||||
reader.setInput(redSquare.getInputStream());
|
||||
BufferedImage imageRed = reader.read(0, param);
|
||||
assertEquals(0xFF0000, imageRed.getRGB(50, 50) & 0xFFFFFF);
|
||||
assertRGBEquals("Expected all red", 0xFF0000, imageRed.getRGB(50, 50) & 0xFFFFFF, 0);
|
||||
|
||||
TestData blueSquare = new TestData(getClassLoaderResource("/svg/blue-square.svg"), dim);
|
||||
reader.setInput(blueSquare.getInputStream());
|
||||
BufferedImage imageBlue = reader.read(0, param);
|
||||
assertEquals(0x0000FF, imageBlue.getRGB(50, 50) & 0xFFFFFF);
|
||||
assertRGBEquals("Expected all blue", 0x0000FF, imageBlue.getRGB(50, 50) & 0xFFFFFF, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -337,4 +339,69 @@ public class SVGImageReaderTest extends ImageReaderAbstractTest<SVGImageReader>
|
||||
reader.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadWitSourceRenderSize() throws IOException {
|
||||
URL resource = getClassLoaderResource("/svg/circle.svg");
|
||||
|
||||
SVGImageReader reader = createReader();
|
||||
|
||||
TestData data = new TestData(resource, (Dimension) null);
|
||||
try (ImageInputStream stream = data.getInputStream()) {
|
||||
reader.setInput(stream);
|
||||
|
||||
SVGReadParam param = reader.getDefaultReadParam();
|
||||
param.setSourceRenderSize(new Dimension(100, 100));
|
||||
BufferedImage image = reader.read(0, param);
|
||||
|
||||
assertNotNull(image);
|
||||
assertEquals(100, image.getWidth());
|
||||
assertEquals(100, image.getHeight());
|
||||
|
||||
// Some quick samples
|
||||
assertRGBEquals("Expected transparent corner", 0, image.getRGB(0, 0), 0);
|
||||
assertRGBEquals("Expected transparent corner", 0, image.getRGB(99, 0), 0);
|
||||
assertRGBEquals("Expected transparent corner", 0, image.getRGB(0, 99), 0);
|
||||
assertRGBEquals("Expected transparent corner", 0, image.getRGB(99, 99), 0);
|
||||
assertRGBEquals("Expected red center", 0xffff0000, image.getRGB(50, 50), 0);
|
||||
}
|
||||
finally {
|
||||
reader.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadWitSourceRenderSizeViewBoxNegativeXY() throws IOException {
|
||||
URL resource = getClassLoaderResource("/svg/Android_robot.svg");
|
||||
|
||||
SVGImageReader reader = createReader();
|
||||
|
||||
TestData data = new TestData(resource, (Dimension) null);
|
||||
try (ImageInputStream stream = data.getInputStream()) {
|
||||
reader.setInput(stream);
|
||||
|
||||
SVGReadParam param = reader.getDefaultReadParam();
|
||||
param.setSourceRenderSize(new Dimension(219, 256)); // Aspect scaled to 256 boxed
|
||||
BufferedImage image = reader.read(0, param);
|
||||
|
||||
assertNotNull(image);
|
||||
assertEquals(219, image.getWidth());
|
||||
assertEquals(256, image.getHeight());
|
||||
|
||||
// Some quick samples
|
||||
assertRGBEquals("Expected transparent corner", 0, image.getRGB(0, 0), 0);
|
||||
assertRGBEquals("Expected transparent corner", 0, image.getRGB(218, 0), 0);
|
||||
assertRGBEquals("Expected transparent corner", 0, image.getRGB(0, 255), 0);
|
||||
assertRGBEquals("Expected transparent corner", 0, image.getRGB(218, 255), 0);
|
||||
assertRGBEquals("Expected green head", 0xffa4c639, image.getRGB(109, 20), 25);
|
||||
assertRGBEquals("Expected green center", 0xffa4c639, image.getRGB(109, 128), 25);
|
||||
assertRGBEquals("Expected green feet", 0xffa4c639, image.getRGB(80, 246), 25);
|
||||
assertRGBEquals("Expected green feet", 0xffa4c639, image.getRGB(130, 246), 25);
|
||||
assertRGBEquals("Expected white edge", 0xffffffff, image.getRGB(0, 128), 0);
|
||||
assertRGBEquals("Expected white edge", 0xffffffff, image.getRGB(218, 128), 0);
|
||||
}
|
||||
finally {
|
||||
reader.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 50 50" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||
xml:space="preserve"
|
||||
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2">
|
||||
<circle cx="25" cy="25" r="25" fill="red"/></svg>
|
||||
|
After Width: | Height: | Size: 436 B |
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<version>3.8.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-bmp</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: BMP plugin</name>
|
||||
|
||||
+16
-9
@@ -39,7 +39,11 @@ import com.twelvemonkeys.io.LittleEndianDataInputStream;
|
||||
import com.twelvemonkeys.io.enc.DecoderStream;
|
||||
import com.twelvemonkeys.xml.XMLSerializer;
|
||||
|
||||
import javax.imageio.*;
|
||||
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;
|
||||
@@ -47,7 +51,7 @@ import javax.imageio.metadata.IIOMetadataFormatImpl;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.awt.*;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.color.*;
|
||||
import java.awt.image.*;
|
||||
import java.io.DataInput;
|
||||
import java.io.File;
|
||||
@@ -77,7 +81,7 @@ public final class BMPImageReader extends ImageReaderBase {
|
||||
super(new BMPImageReaderSpi());
|
||||
}
|
||||
|
||||
protected BMPImageReader(final ImageReaderSpi pProvider) {
|
||||
BMPImageReader(final ImageReaderSpi pProvider) {
|
||||
super(pProvider);
|
||||
}
|
||||
|
||||
@@ -358,14 +362,18 @@ public final class BMPImageReader extends ImageReaderBase {
|
||||
|
||||
processImageStarted(imageIndex);
|
||||
for (int y = 0; y < height; y++) {
|
||||
switch (header.getBitCount()) {
|
||||
int bitCount = header.getBitCount();
|
||||
switch (bitCount) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
case 24:
|
||||
byte[] rowDataByte = ((DataBufferByte) rowRaster.getDataBuffer()).getData();
|
||||
readRowByte(input, height, srcRegion, xSub, ySub, rowDataByte, destRaster, clippedRow, y);
|
||||
int bitsPerSample = bitCount == 24 ? 8 : bitCount;
|
||||
int samplesPerPixel = bitCount == 24 ? 3 : 1;
|
||||
|
||||
readRowByte(input, height, srcRegion, xSub, ySub, bitsPerSample, samplesPerPixel, rowDataByte, destRaster, clippedRow, y);
|
||||
break;
|
||||
|
||||
case 16:
|
||||
@@ -379,7 +387,7 @@ public final class BMPImageReader extends ImageReaderBase {
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new AssertionError("Unsupported pixel depth: " + header.getBitCount());
|
||||
throw new AssertionError("Unsupported pixel depth: " + bitCount);
|
||||
}
|
||||
|
||||
processImageProgress(100f * y / height);
|
||||
@@ -476,6 +484,7 @@ public final class BMPImageReader extends ImageReaderBase {
|
||||
}
|
||||
|
||||
private void readRowByte(final DataInput input, final int height, final Rectangle srcRegion, final int xSub, final int ySub,
|
||||
int bitsPerSample, int samplesPerPixel,
|
||||
final byte[] rowDataByte, final WritableRaster destChannel, final Raster srcChannel, final int y) throws IOException {
|
||||
// Flip into position?
|
||||
int srcY = !header.topDown ? height - 1 - y : y;
|
||||
@@ -492,9 +501,7 @@ public final class BMPImageReader extends ImageReaderBase {
|
||||
|
||||
// Subsample horizontal
|
||||
if (xSub != 1) {
|
||||
for (int x = 0; x < srcRegion.width / xSub; x++) {
|
||||
rowDataByte[srcRegion.x + x] = rowDataByte[srcRegion.x + x * xSub];
|
||||
}
|
||||
IIOUtil.subsampleRow(rowDataByte, srcRegion.x, srcRegion.width, rowDataByte, 0, samplesPerPixel, bitsPerSample, xSub);
|
||||
}
|
||||
|
||||
destChannel.setDataElements(0, dstY, srcChannel);
|
||||
|
||||
+1
-1
@@ -116,7 +116,7 @@ public final class BMPImageReaderSpi extends ImageReaderSpiBase {
|
||||
}
|
||||
}
|
||||
|
||||
public ImageReader createReaderInstance(final Object pExtension) throws IOException {
|
||||
public ImageReader createReaderInstance(final Object pExtension) {
|
||||
return new BMPImageReader(this);
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 257 KiB |
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<version>3.8.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-clippath</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: Photoshop Path Support</name>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<version>3.8.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-core</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: Core</name>
|
||||
|
||||
+20
-20
@@ -54,8 +54,8 @@ public final class DiscreteAlphaIndexColorModel extends ColorModel {
|
||||
// Our IndexColorModel delegate
|
||||
private final IndexColorModel icm;
|
||||
|
||||
private final int extraSamples;
|
||||
private final int samples;
|
||||
private final boolean hasAlpha;
|
||||
|
||||
/**
|
||||
* Creates a {@code DiscreteAlphaIndexColorModel}, delegating color map look-ups
|
||||
@@ -86,33 +86,33 @@ public final class DiscreteAlphaIndexColorModel extends ColorModel {
|
||||
);
|
||||
|
||||
this.icm = icm;
|
||||
this.extraSamples = extraSamples;
|
||||
this.samples = 1 + extraSamples;
|
||||
this.hasAlpha = hasAlpha;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumComponents() {
|
||||
return samples;
|
||||
return getNumColorComponents() + extraSamples;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getRed(final int pixel) {
|
||||
public int getRed(final int pixel) {
|
||||
return icm.getRed(pixel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getGreen(final int pixel) {
|
||||
public int getGreen(final int pixel) {
|
||||
return icm.getGreen(pixel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getBlue(final int pixel) {
|
||||
public int getBlue(final int pixel) {
|
||||
return icm.getBlue(pixel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getAlpha(final int pixel) {
|
||||
return hasAlpha ? (int) ((((float) pixel) / ((1 << getComponentSize(3))-1)) * 255.0f + 0.5f) : 0xff;
|
||||
public int getAlpha(final int pixel) {
|
||||
return hasAlpha() ? (int) ((((float) pixel) / ((1 << getComponentSize(3)) - 1)) * 255.0f + 0.5f) : 0xff;
|
||||
}
|
||||
|
||||
private int getSample(final Object inData, final int index) {
|
||||
@@ -120,15 +120,15 @@ public final class DiscreteAlphaIndexColorModel extends ColorModel {
|
||||
|
||||
switch (transferType) {
|
||||
case DataBuffer.TYPE_BYTE:
|
||||
byte bdata[] = (byte[]) inData;
|
||||
byte[] bdata = (byte[]) inData;
|
||||
pixel = bdata[index] & 0xff;
|
||||
break;
|
||||
case DataBuffer.TYPE_USHORT:
|
||||
short sdata[] = (short[]) inData;
|
||||
short[] sdata = (short[]) inData;
|
||||
pixel = sdata[index] & 0xffff;
|
||||
break;
|
||||
case DataBuffer.TYPE_INT:
|
||||
int idata[] = (int[]) inData;
|
||||
int[] idata = (int[]) inData;
|
||||
pixel = idata[index];
|
||||
break;
|
||||
default:
|
||||
@@ -139,27 +139,27 @@ public final class DiscreteAlphaIndexColorModel extends ColorModel {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getRed(final Object inData) {
|
||||
public int getRed(final Object inData) {
|
||||
return getRed(getSample(inData, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getGreen(final Object inData) {
|
||||
public int getGreen(final Object inData) {
|
||||
return getGreen(getSample(inData, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getBlue(final Object inData) {
|
||||
public int getBlue(final Object inData) {
|
||||
return getBlue(getSample(inData, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getAlpha(final Object inData) {
|
||||
return hasAlpha ? getAlpha(getSample(inData, 1)) : 0xff;
|
||||
public int getAlpha(final Object inData) {
|
||||
return hasAlpha() ? getAlpha(getSample(inData, 1)) : 0xff;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final SampleModel createCompatibleSampleModel(final int w, final int h) {
|
||||
public SampleModel createCompatibleSampleModel(final int w, final int h) {
|
||||
return new PixelInterleavedSampleModel(transferType, w, h, samples, w * samples, createOffsets(samples));
|
||||
}
|
||||
|
||||
@@ -174,17 +174,17 @@ public final class DiscreteAlphaIndexColorModel extends ColorModel {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isCompatibleSampleModel(final SampleModel sm) {
|
||||
public boolean isCompatibleSampleModel(final SampleModel sm) {
|
||||
return sm instanceof PixelInterleavedSampleModel && sm.getNumBands() == samples;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WritableRaster createCompatibleWritableRaster(final int w, final int h) {
|
||||
public WritableRaster createCompatibleWritableRaster(final int w, final int h) {
|
||||
return Raster.createWritableRaster(createCompatibleSampleModel(w, h), new Point(0, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isCompatibleRaster(final Raster raster) {
|
||||
public boolean isCompatibleRaster(final Raster raster) {
|
||||
int size = raster.getSampleModel().getSampleSize(0);
|
||||
return ((raster.getTransferType() == transferType) &&
|
||||
(raster.getNumBands() == samples) && ((1 << size) >= icm.getMapSize()));
|
||||
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.stream;
|
||||
|
||||
import javax.imageio.stream.ImageInputStreamImpl;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import static com.twelvemonkeys.lang.Validate.isTrue;
|
||||
import static com.twelvemonkeys.lang.Validate.notNull;
|
||||
|
||||
/**
|
||||
* An {@code ImageInputStream} that adapts an {@code InputSteam},
|
||||
* by reading directly from the stream without and form of caching or buffering.
|
||||
* <p>
|
||||
* Note: This is <em>not</em> a general-purpose {@code ImageInputStream}, and is designed for reading large chunks,
|
||||
* typically of pixel data, from an {@code InputStream}.
|
||||
* It does <em>not</em> support backwards seeking, or reading bits.
|
||||
* </p>
|
||||
*/
|
||||
public final class DirectImageInputStream extends ImageInputStreamImpl {
|
||||
private final InputStream stream;
|
||||
private final long length;
|
||||
|
||||
public DirectImageInputStream(final InputStream stream) {
|
||||
this(stream, -1L);
|
||||
}
|
||||
|
||||
public DirectImageInputStream(final InputStream stream, long length) {
|
||||
this.stream = notNull(stream, "stream");
|
||||
this.length = isTrue(length >= 0L || length == -1L, length, "negative length: %d");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
bitOffset = 0;
|
||||
streamPos++;
|
||||
return stream.read();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(final byte[] bytes, int off, int len) throws IOException {
|
||||
bitOffset = 0;
|
||||
|
||||
int read = stream.read(bytes, off, len);
|
||||
if (read > 0) {
|
||||
streamPos += read;
|
||||
}
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seek(long pos) throws IOException {
|
||||
checkClosed();
|
||||
|
||||
if (pos < streamPos) {
|
||||
// Handle as if flushedPos == streamPos at any time
|
||||
throw new IndexOutOfBoundsException("pos < flushedPos");
|
||||
}
|
||||
|
||||
bitOffset = 0;
|
||||
|
||||
while (streamPos < pos) {
|
||||
long skipped = stream.skip(pos - streamPos);
|
||||
|
||||
if (skipped <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
streamPos += skipped;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFlushedPosition() {
|
||||
// Handle as if flushedPos == streamPos at any time
|
||||
return streamPos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long length() {
|
||||
return length;
|
||||
}
|
||||
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
@Override
|
||||
public int readBit() throws IOException {
|
||||
throw new UnsupportedOperationException("Bit reading not supported");
|
||||
}
|
||||
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
@Override
|
||||
public long readBits(int numBits) throws IOException {
|
||||
throw new UnsupportedOperationException("Bit reading not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
// We could seek to EOF here, but the usual case
|
||||
|
||||
stream.close();
|
||||
super.close();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -81,7 +81,7 @@ class IIOInputStreamAdapter extends InputStream {
|
||||
|
||||
private IIOInputStreamAdapter(ImageInputStream pInput, long pLength, boolean pHasLength) {
|
||||
Validate.notNull(pInput, "stream");
|
||||
Validate.isTrue(!pHasLength || pLength >= 0, pLength, "length < 0: %f");
|
||||
Validate.isTrue(!pHasLength || pLength >= 0, pLength, "length < 0: %d");
|
||||
|
||||
input = pInput;
|
||||
left = pLength;
|
||||
|
||||
@@ -45,6 +45,7 @@ import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Iterator;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
@@ -175,15 +176,22 @@ public final class IIOUtil {
|
||||
* @param providerClassName name of the provider class.
|
||||
* @param category provider category
|
||||
*
|
||||
* @return the provider instance, or {@code null}.
|
||||
* @return the provider instance, or {@code null} if not found
|
||||
*/
|
||||
public static <T> T lookupProviderByName(final ServiceRegistry registry, final String providerClassName, Class<T> category) {
|
||||
try {
|
||||
return category.cast(registry.getServiceProviderByClass(Class.forName(providerClassName)));
|
||||
}
|
||||
catch (ClassNotFoundException ignore) {
|
||||
return null;
|
||||
// NOTE: While more verbose, this is more OSGi-friendly than using
|
||||
// registry.getServiceProviderByClass(Class.forName(providerClassName))
|
||||
Iterator<T> providers = registry.getServiceProviders(category, true);
|
||||
|
||||
while (providers.hasNext()) {
|
||||
T provider = providers.next();
|
||||
|
||||
if (provider.getClass().getName().equals(providerClassName)) {
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+22
-1
@@ -37,7 +37,9 @@ 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.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class DiscreteAlphaIndexColorModelTest {
|
||||
|
||||
@@ -204,6 +206,25 @@ public class DiscreteAlphaIndexColorModelTest {
|
||||
assertThat(raster.getTransferType(), CoreMatchers.equalTo(DataBuffer.TYPE_BYTE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNumComponents() {
|
||||
int[] colors = createIntLut(1 << 8);
|
||||
IndexColorModel icm = new IndexColorModel(8, colors.length, colors, 0, false, -1, DataBuffer.TYPE_BYTE);
|
||||
|
||||
ColorModel colorModelDiscreteAlpha = new DiscreteAlphaIndexColorModel(icm, 1, true);
|
||||
ColorModel colorModelDiscreteAlphaExtra = new DiscreteAlphaIndexColorModel(icm, 2, true);
|
||||
ColorModel colorModelNoAlphaExtra = new DiscreteAlphaIndexColorModel(icm, 42, false);
|
||||
|
||||
assertEquals(3, colorModelDiscreteAlpha.getNumColorComponents());
|
||||
assertEquals(4, colorModelDiscreteAlpha.getNumComponents());
|
||||
|
||||
assertEquals(3, colorModelDiscreteAlphaExtra.getNumColorComponents());
|
||||
assertEquals(5, colorModelDiscreteAlphaExtra.getNumComponents()); // Questionable
|
||||
|
||||
assertEquals(3, colorModelNoAlphaExtra.getNumColorComponents());
|
||||
assertEquals(45, colorModelNoAlphaExtra.getNumComponents()); // Questionable
|
||||
}
|
||||
|
||||
private static int[] createIntLut(final int count) {
|
||||
int[] lut = new int[count];
|
||||
|
||||
|
||||
+2
-1
@@ -53,6 +53,7 @@ import static org.mockito.Mockito.*;
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: BufferedImageInputStreamTest.java,v 1.0 Jun 30, 2008 3:07:42 PM haraldk Exp$
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class BufferedImageInputStreamTest {
|
||||
private final Random random = new Random(3450972865211L);
|
||||
|
||||
@@ -433,7 +434,7 @@ public class BufferedImageInputStreamTest {
|
||||
* and {@code pFirstOffset == pSecondOffset}.
|
||||
* Otherwise {@code false}.
|
||||
*/
|
||||
static boolean rangeEquals(byte[] pFirst, int pFirstOffset, byte[] pSecond, int pSecondOffset, int pLength) {
|
||||
public static boolean rangeEquals(byte[] pFirst, int pFirstOffset, byte[] pSecond, int pSecondOffset, int pLength) {
|
||||
if (pFirst == pSecond && pFirstOffset == pSecondOffset) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Executable
+380
@@ -0,0 +1,380 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.stream;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.function.ThrowingRunnable;
|
||||
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Random;
|
||||
|
||||
import static com.twelvemonkeys.imageio.stream.BufferedImageInputStreamTest.rangeEquals;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
* NonSeekableImageInputStreamTest
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: NonSeekableImageInputStreamTest.java,v 1.0 Apr 21, 2009 10:58:48 AM haraldk Exp$
|
||||
*/
|
||||
public class DirectImageInputStreamTest {
|
||||
private final Random random = new Random(170984354357234566L);
|
||||
|
||||
private InputStream randomData(byte[] data) {
|
||||
random.nextBytes(data);
|
||||
|
||||
return new ByteArrayInputStream(data);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreate() throws IOException {
|
||||
try (DirectImageInputStream stream = new DirectImageInputStream(new ByteArrayInputStream(new byte[0]), 0)) {
|
||||
assertEquals("Data length should be same as stream length", 0, stream.length());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateNullFile() throws IOException {
|
||||
try (@SuppressWarnings("unused") DirectImageInputStream stream = new DirectImageInputStream(null)) {
|
||||
fail("Expected IllegalArgumentException");
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertNotNull("Null exception message", expected.getMessage());
|
||||
String message = expected.getMessage().toLowerCase();
|
||||
assertTrue("Exception message does not contain parameter name", message.contains("stream"));
|
||||
assertTrue("Exception message does not contain null", message.contains("null"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRead() throws IOException {
|
||||
byte[] data = new byte[1024 * 1024];
|
||||
InputStream input = randomData(data);
|
||||
|
||||
try (DirectImageInputStream stream = new DirectImageInputStream(input)) {
|
||||
for (byte value : data) {
|
||||
assertEquals("Wrong data read", value & 0xff, stream.read());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadArray() throws IOException {
|
||||
byte[] data = new byte[1024 * 10];
|
||||
InputStream input = randomData(data);
|
||||
|
||||
try (DirectImageInputStream stream = new DirectImageInputStream(input)) {
|
||||
byte[] result = new byte[1024];
|
||||
|
||||
for (int i = 0; i < data.length / result.length; i++) {
|
||||
stream.readFully(result);
|
||||
assertTrue("Wrong data read: " + i, rangeEquals(data, i * result.length, result, 0, result.length));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadSkip() throws IOException {
|
||||
byte[] data = new byte[1024 * 14];
|
||||
InputStream input = randomData(data);
|
||||
|
||||
try (DirectImageInputStream stream = new DirectImageInputStream(input)) {
|
||||
byte[] result = new byte[7];
|
||||
|
||||
for (int i = 0; i < data.length / result.length; i += 2) {
|
||||
stream.readFully(result);
|
||||
stream.skipBytes(result.length);
|
||||
assertTrue("Wrong data read: " + i, rangeEquals(data, i * result.length, result, 0, result.length));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadSeek() throws IOException {
|
||||
byte[] data = new byte[24 * 18];
|
||||
InputStream input = randomData(data);
|
||||
|
||||
try (DirectImageInputStream stream = new DirectImageInputStream(input)) {
|
||||
byte[] result = new byte[9];
|
||||
|
||||
for (int i = 0; i < data.length / (2 * result.length); i++) {
|
||||
long newPos = i * 2 * result.length;
|
||||
stream.seek(newPos);
|
||||
assertEquals("Wrong stream position", newPos, stream.getStreamPosition());
|
||||
stream.readFully(result);
|
||||
assertTrue("Wrong data read: " + i, rangeEquals(data, (int) newPos, result, 0, result.length));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Ignore("Bit reading requires backwards seek or buffer...")
|
||||
@Test
|
||||
public void testReadBitRandom() throws IOException {
|
||||
byte[] bytes = new byte[8];
|
||||
InputStream input = randomData(bytes);
|
||||
long value = ByteBuffer.wrap(bytes).getLong();
|
||||
|
||||
// Create stream
|
||||
try (DirectImageInputStream stream = new DirectImageInputStream(input)) {
|
||||
for (int i = 1; i <= 64; i++) {
|
||||
assertEquals(String.format("bit %d differ", i), (value << (i - 1L)) >>> 63L, stream.readBit());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Ignore("Bit reading requires backwards seek or buffer...")
|
||||
@Test
|
||||
public void testReadBitsRandom() throws IOException {
|
||||
byte[] bytes = new byte[8];
|
||||
InputStream input = randomData(bytes);
|
||||
long value = ByteBuffer.wrap(bytes).getLong();
|
||||
|
||||
// Create stream
|
||||
try (DirectImageInputStream stream = new DirectImageInputStream(input)) {
|
||||
for (int i = 1; i <= 64; i++) {
|
||||
stream.seek(0);
|
||||
assertEquals(String.format("bit %d differ", i), value >>> (64L - i), stream.readBits(i));
|
||||
assertEquals(i % 8, stream.getBitOffset());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Ignore("Bit reading requires backwards seek or buffer...")
|
||||
@Test
|
||||
public void testReadBitsRandomOffset() throws IOException {
|
||||
byte[] bytes = new byte[8];
|
||||
InputStream input = randomData(bytes);
|
||||
long value = ByteBuffer.wrap(bytes).getLong();
|
||||
|
||||
// Create stream
|
||||
try (DirectImageInputStream stream = new DirectImageInputStream(input)) {
|
||||
for (int i = 1; i <= 60; i++) {
|
||||
stream.seek(0);
|
||||
stream.setBitOffset(i % 8);
|
||||
assertEquals(String.format("bit %d differ", i), (value << (i % 8)) >>> (64L - i), stream.readBits(i));
|
||||
assertEquals(i * 2L % 8, stream.getBitOffset());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadShort() throws IOException {
|
||||
byte[] bytes = new byte[31];
|
||||
InputStream input = randomData(bytes);
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
|
||||
|
||||
try (DirectImageInputStream stream = new DirectImageInputStream(input)) {
|
||||
stream.setByteOrder(ByteOrder.BIG_ENDIAN);
|
||||
|
||||
for (int i = 0; i < bytes.length / 2; i++) {
|
||||
assertEquals(buffer.getShort(), stream.readShort());
|
||||
}
|
||||
|
||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
||||
@Override
|
||||
public void run() throws Throwable {
|
||||
stream.readShort();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
try (DirectImageInputStream stream = new DirectImageInputStream(new ByteArrayInputStream(bytes))) {
|
||||
stream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
||||
buffer.position(0);
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
for (int i = 0; i < bytes.length / 2; i++) {
|
||||
assertEquals(buffer.getShort(), stream.readShort());
|
||||
}
|
||||
|
||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
||||
@Override
|
||||
public void run() throws Throwable {
|
||||
stream.readShort();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadInt() throws IOException {
|
||||
byte[] bytes = new byte[31];
|
||||
InputStream input = randomData(bytes);
|
||||
ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
|
||||
|
||||
// Create stream
|
||||
try (DirectImageInputStream stream = new DirectImageInputStream(input)) {
|
||||
stream.setByteOrder(ByteOrder.BIG_ENDIAN);
|
||||
|
||||
for (int i = 0; i < bytes.length / 4; i++) {
|
||||
assertEquals(buffer.getInt(), stream.readInt());
|
||||
}
|
||||
|
||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
||||
@Override
|
||||
public void run() throws Throwable {
|
||||
stream.readInt();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
try (DirectImageInputStream stream = new DirectImageInputStream(new ByteArrayInputStream(bytes))) {
|
||||
stream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
||||
buffer.position(0);
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
for (int i = 0; i < bytes.length / 4; i++) {
|
||||
assertEquals(buffer.getInt(), stream.readInt());
|
||||
}
|
||||
|
||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
||||
@Override
|
||||
public void run() throws Throwable {
|
||||
stream.readInt();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadLong() throws IOException {
|
||||
byte[] bytes = new byte[8743]; // Slightly more than one buffer size
|
||||
InputStream input = randomData(bytes);
|
||||
ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
|
||||
|
||||
try (DirectImageInputStream stream = new DirectImageInputStream(input)) {
|
||||
stream.setByteOrder(ByteOrder.BIG_ENDIAN);
|
||||
|
||||
for (int i = 0; i < bytes.length / 8; i++) {
|
||||
assertEquals(buffer.getLong(), stream.readLong());
|
||||
}
|
||||
|
||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
||||
@Override
|
||||
public void run() throws Throwable {
|
||||
stream.readLong();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
try (DirectImageInputStream stream = new DirectImageInputStream(new ByteArrayInputStream(bytes))) {
|
||||
stream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
||||
buffer.position(0);
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
for (int i = 0; i < bytes.length / 8; i++) {
|
||||
assertEquals(buffer.getLong(), stream.readLong());
|
||||
}
|
||||
|
||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
||||
@Override
|
||||
public void run() throws Throwable {
|
||||
stream.readLong();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSeekPastEOF() throws IOException {
|
||||
byte[] bytes = new byte[9];
|
||||
InputStream input = randomData(bytes);
|
||||
|
||||
try (DirectImageInputStream stream = new DirectImageInputStream(input)) {
|
||||
stream.seek(1000);
|
||||
|
||||
assertEquals(-1, stream.read());
|
||||
assertEquals(-1, stream.read(new byte[1], 0, 1));
|
||||
|
||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
||||
@Override
|
||||
public void run() throws Throwable {
|
||||
stream.readFully(new byte[1]);
|
||||
}
|
||||
});
|
||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
||||
@Override
|
||||
public void run() throws Throwable {
|
||||
stream.readByte();
|
||||
}
|
||||
});
|
||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
||||
@Override
|
||||
public void run() throws Throwable {
|
||||
stream.readShort();
|
||||
}
|
||||
});
|
||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
||||
@Override
|
||||
public void run() throws Throwable {
|
||||
stream.readInt();
|
||||
}
|
||||
});
|
||||
assertThrows(EOFException.class, new ThrowingRunnable() {
|
||||
@Override
|
||||
public void run() throws Throwable {
|
||||
stream.readLong();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
try (DirectImageInputStream stream = new DirectImageInputStream(new ByteArrayInputStream(bytes))) {
|
||||
for (byte value : bytes) {
|
||||
assertEquals(value, stream.readByte());
|
||||
}
|
||||
|
||||
assertEquals(-1, stream.read());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClose() throws IOException {
|
||||
// Create wrapper stream
|
||||
InputStream input = mock(InputStream.class);
|
||||
ImageInputStream stream = new DirectImageInputStream(input);
|
||||
|
||||
stream.close();
|
||||
verify(input, only()).close();
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<version>3.8.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-hdr</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: HDR plugin</name>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<version>3.8.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-icns</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: ICNS plugin</name>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<version>3.8.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-iff</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: IFF plugin</name>
|
||||
|
||||
+6
-6
@@ -69,14 +69,14 @@ abstract class AbstractMultiPaletteChunk extends IFFChunk implements MultiPalett
|
||||
protected WeakReference<IndexColorModel> originalPalette;
|
||||
protected MutableIndexColorModel mutablePalette;
|
||||
|
||||
public AbstractMultiPaletteChunk(int pChunkId, int pChunkLength) {
|
||||
super(pChunkId, pChunkLength);
|
||||
public AbstractMultiPaletteChunk(int chunkId, int chunkLength) {
|
||||
super(chunkId, chunkLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
void readChunk(final DataInput pInput) throws IOException {
|
||||
void readChunk(final DataInput input) throws IOException {
|
||||
if (chunkId == IFF.CHUNK_SHAM) {
|
||||
pInput.readUnsignedShort(); // Version, typically 0, skipped
|
||||
input.readUnsignedShort(); // Version, typically 0, skipped
|
||||
}
|
||||
|
||||
int rows = chunkLength / 32; /* sizeof(word) * 16 */
|
||||
@@ -91,7 +91,7 @@ abstract class AbstractMultiPaletteChunk extends IFFChunk implements MultiPalett
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++ ) {
|
||||
int data = pInput.readUnsignedShort();
|
||||
int data = input.readUnsignedShort();
|
||||
|
||||
changes[row][i].index = i;
|
||||
changes[row][i].r = (byte) (((data & 0x0f00) >> 8) * FACTOR_4BIT);
|
||||
@@ -102,7 +102,7 @@ abstract class AbstractMultiPaletteChunk extends IFFChunk implements MultiPalett
|
||||
}
|
||||
|
||||
@Override
|
||||
void writeChunk(DataOutput pOutput) {
|
||||
void writeChunk(DataOutput output) {
|
||||
throw new UnsupportedOperationException("Method writeChunk not implemented");
|
||||
}
|
||||
|
||||
|
||||
+43
-43
@@ -30,12 +30,11 @@
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
|
||||
/**
|
||||
* BMHDChunk
|
||||
*
|
||||
@@ -110,64 +109,65 @@ final class BMHDChunk extends IFFChunk {
|
||||
int pageWidth;
|
||||
int pageHeight;
|
||||
|
||||
protected BMHDChunk(int pChunkLength) {
|
||||
super(IFF.CHUNK_BMHD, pChunkLength);
|
||||
BMHDChunk(int chunkLength) {
|
||||
super(IFF.CHUNK_BMHD, chunkLength);
|
||||
}
|
||||
|
||||
protected BMHDChunk(int pWidth, int pHeight, int pBitplanes, int pMaskType, int pCompressionType, int pTransparentIndex) {
|
||||
BMHDChunk(int width, int height, int bitplanes, int maskType, int compressionType, int transparentIndex) {
|
||||
super(IFF.CHUNK_BMHD, 20);
|
||||
width = pWidth;
|
||||
height = pHeight;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
xPos = 0;
|
||||
yPos = 0;
|
||||
bitplanes = pBitplanes;
|
||||
maskType = pMaskType;
|
||||
compressionType = pCompressionType;
|
||||
transparentIndex = pTransparentIndex;
|
||||
this.bitplanes = bitplanes;
|
||||
this.maskType = maskType;
|
||||
this.compressionType = compressionType;
|
||||
this.transparentIndex = transparentIndex;
|
||||
xAspect = 1;
|
||||
yAspect = 1;
|
||||
pageWidth = Math.min(pWidth, Short.MAX_VALUE); // For some reason, these are signed?
|
||||
pageHeight = Math.min(pHeight, Short.MAX_VALUE);
|
||||
pageWidth = Math.min(width, Short.MAX_VALUE); // For some reason, these are signed?
|
||||
pageHeight = Math.min(height, Short.MAX_VALUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
void readChunk(final DataInput pInput) throws IOException {
|
||||
void readChunk(final DataInput input) throws IOException {
|
||||
if (chunkLength != 20) {
|
||||
throw new IIOException("Unknown BMHD chunk length: " + chunkLength);
|
||||
}
|
||||
width = pInput.readUnsignedShort();
|
||||
height = pInput.readUnsignedShort();
|
||||
xPos = pInput.readShort();
|
||||
yPos = pInput.readShort();
|
||||
bitplanes = pInput.readUnsignedByte();
|
||||
maskType = pInput.readUnsignedByte();
|
||||
compressionType = pInput.readUnsignedByte();
|
||||
pInput.readByte(); // PAD
|
||||
transparentIndex = pInput.readUnsignedShort();
|
||||
xAspect = pInput.readUnsignedByte();
|
||||
yAspect = pInput.readUnsignedByte();
|
||||
pageWidth = pInput.readShort();
|
||||
pageHeight = pInput.readShort();
|
||||
|
||||
width = input.readUnsignedShort();
|
||||
height = input.readUnsignedShort();
|
||||
xPos = input.readShort();
|
||||
yPos = input.readShort();
|
||||
bitplanes = input.readUnsignedByte();
|
||||
maskType = input.readUnsignedByte();
|
||||
compressionType = input.readUnsignedByte();
|
||||
input.readByte(); // PAD
|
||||
transparentIndex = input.readUnsignedShort();
|
||||
xAspect = input.readUnsignedByte();
|
||||
yAspect = input.readUnsignedByte();
|
||||
pageWidth = input.readShort();
|
||||
pageHeight = input.readShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
void writeChunk(final DataOutput pOutput) throws IOException {
|
||||
pOutput.writeInt(chunkId);
|
||||
pOutput.writeInt(chunkLength);
|
||||
void writeChunk(final DataOutput output) throws IOException {
|
||||
output.writeInt(chunkId);
|
||||
output.writeInt(chunkLength);
|
||||
|
||||
pOutput.writeShort(width);
|
||||
pOutput.writeShort(height);
|
||||
pOutput.writeShort(xPos);
|
||||
pOutput.writeShort(yPos);
|
||||
pOutput.writeByte(bitplanes);
|
||||
pOutput.writeByte(maskType);
|
||||
pOutput.writeByte(compressionType);
|
||||
pOutput.writeByte(0); // PAD
|
||||
pOutput.writeShort(transparentIndex);
|
||||
pOutput.writeByte(xAspect);
|
||||
pOutput.writeByte(yAspect);
|
||||
pOutput.writeShort(pageWidth);
|
||||
pOutput.writeShort(pageHeight);
|
||||
output.writeShort(width);
|
||||
output.writeShort(height);
|
||||
output.writeShort(xPos);
|
||||
output.writeShort(yPos);
|
||||
output.writeByte(bitplanes);
|
||||
output.writeByte(maskType);
|
||||
output.writeByte(compressionType);
|
||||
output.writeByte(0); // PAD
|
||||
output.writeShort(transparentIndex);
|
||||
output.writeByte(xAspect);
|
||||
output.writeByte(yAspect);
|
||||
output.writeShort(pageWidth);
|
||||
output.writeShort(pageHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+9
-4
@@ -33,6 +33,8 @@ package com.twelvemonkeys.imageio.plugins.iff;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
|
||||
import static com.twelvemonkeys.lang.Validate.isTrue;
|
||||
|
||||
/**
|
||||
* BODYChunk
|
||||
*
|
||||
@@ -40,17 +42,20 @@ import java.io.DataOutput;
|
||||
* @version $Id: BODYChunk.java,v 1.0 28.feb.2006 01:25:49 haku Exp$
|
||||
*/
|
||||
final class BODYChunk extends IFFChunk {
|
||||
protected BODYChunk(int pChunkLength) {
|
||||
super(IFF.CHUNK_BODY, pChunkLength);
|
||||
final long chunkOffset;
|
||||
|
||||
BODYChunk(int chunkId, int chunkLength, long chunkOffset) {
|
||||
super(isTrue(chunkId == IFF.CHUNK_BODY || chunkId == IFF.CHUNK_DBOD, chunkId, "Illegal body chunk: '%s'"), chunkLength);
|
||||
this.chunkOffset = chunkOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
void readChunk(final DataInput pInput) {
|
||||
void readChunk(final DataInput input) {
|
||||
throw new InternalError("BODY chunk should only be read from IFFImageReader");
|
||||
}
|
||||
|
||||
@Override
|
||||
void writeChunk(final DataOutput pOutput) {
|
||||
void writeChunk(final DataOutput output) {
|
||||
throw new InternalError("BODY chunk should only be written from IFFImageWriter");
|
||||
}
|
||||
}
|
||||
|
||||
+6
-7
@@ -30,12 +30,11 @@
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
|
||||
/**
|
||||
* CAMGChunk
|
||||
*
|
||||
@@ -49,21 +48,21 @@ final class CAMGChunk extends IFFChunk {
|
||||
|
||||
int camg;
|
||||
|
||||
public CAMGChunk(int pLength) {
|
||||
super(IFF.CHUNK_CAMG, pLength);
|
||||
CAMGChunk(int chunkLength) {
|
||||
super(IFF.CHUNK_CAMG, chunkLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
void readChunk(final DataInput pInput) throws IOException {
|
||||
void readChunk(final DataInput input) throws IOException {
|
||||
if (chunkLength != 4) {
|
||||
throw new IIOException("Unknown CAMG chunk length: " + chunkLength);
|
||||
}
|
||||
|
||||
camg = pInput.readInt();
|
||||
camg = input.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
void writeChunk(final DataOutput pOutput) {
|
||||
void writeChunk(final DataOutput output) {
|
||||
throw new InternalError("Not implemented: writeChunk()");
|
||||
}
|
||||
|
||||
|
||||
+20
-35
@@ -30,16 +30,13 @@
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import javax.imageio.IIOException;
|
||||
import java.awt.image.IndexColorModel;
|
||||
import java.awt.image.WritableRaster;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
|
||||
/**
|
||||
* CMAPChunk
|
||||
*
|
||||
@@ -60,7 +57,7 @@ final class CMAPChunk extends IFFChunk {
|
||||
|
||||
private IndexColorModel model;
|
||||
|
||||
protected CMAPChunk(final int pChunkLength) {
|
||||
CMAPChunk(final int pChunkLength) {
|
||||
super(IFF.CHUNK_CMAP, pChunkLength);
|
||||
}
|
||||
|
||||
@@ -70,7 +67,7 @@ final class CMAPChunk extends IFFChunk {
|
||||
}
|
||||
|
||||
@Override
|
||||
void readChunk(final DataInput pInput) throws IOException {
|
||||
void readChunk(final DataInput input) throws IOException {
|
||||
int numColors = chunkLength / 3;
|
||||
|
||||
reds = new byte[numColors];
|
||||
@@ -78,9 +75,9 @@ final class CMAPChunk extends IFFChunk {
|
||||
blues = reds.clone();
|
||||
|
||||
for (int i = 0; i < numColors; i++) {
|
||||
reds[i] = pInput.readByte();
|
||||
greens[i] = pInput.readByte();
|
||||
blues[i] = pInput.readByte();
|
||||
reds[i] = input.readByte();
|
||||
greens[i] = input.readByte();
|
||||
blues[i] = input.readByte();
|
||||
}
|
||||
|
||||
// TODO: When reading in a CMAP for 8-bit-per-gun display or
|
||||
@@ -93,25 +90,25 @@ final class CMAPChunk extends IFFChunk {
|
||||
|
||||
// All chunks are WORD aligned (even sized), may need to read pad...
|
||||
if (chunkLength % 2 != 0) {
|
||||
pInput.readByte();
|
||||
input.readByte();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void writeChunk(final DataOutput pOutput) throws IOException {
|
||||
pOutput.writeInt(chunkId);
|
||||
pOutput.writeInt(chunkLength);
|
||||
void writeChunk(final DataOutput output) throws IOException {
|
||||
output.writeInt(chunkId);
|
||||
output.writeInt(chunkLength);
|
||||
|
||||
final int length = model.getMapSize();
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
pOutput.writeByte(model.getRed(i));
|
||||
pOutput.writeByte(model.getGreen(i));
|
||||
pOutput.writeByte(model.getBlue(i));
|
||||
output.writeByte(model.getRed(i));
|
||||
output.writeByte(model.getGreen(i));
|
||||
output.writeByte(model.getBlue(i));
|
||||
}
|
||||
|
||||
if (chunkLength % 2 != 0) {
|
||||
pOutput.writeByte(0); // PAD
|
||||
output.writeByte(0); // PAD
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,25 +117,11 @@ final class CMAPChunk extends IFFChunk {
|
||||
return super.toString() + " {colorMap=" + model + "}";
|
||||
}
|
||||
|
||||
BufferedImage createPaletteImage(final BMHDChunk header, boolean isEHB) throws IIOException {
|
||||
// Create a 1 x colors.length image
|
||||
IndexColorModel cm = getIndexColorModel(header, isEHB);
|
||||
WritableRaster raster = cm.createCompatibleWritableRaster(cm.getMapSize(), 1);
|
||||
byte[] pixel = null;
|
||||
|
||||
for (int x = 0; x < cm.getMapSize(); x++) {
|
||||
pixel = (byte[]) cm.getDataElements(cm.getRGB(x), pixel);
|
||||
raster.setDataElements(x, 0, pixel);
|
||||
}
|
||||
|
||||
return new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
|
||||
}
|
||||
|
||||
public IndexColorModel getIndexColorModel(final BMHDChunk header, boolean isEHB) throws IIOException {
|
||||
public IndexColorModel getIndexColorModel(final Form.ILBMForm header) throws IIOException {
|
||||
if (model == null) {
|
||||
int numColors = reds.length; // All arrays are same size
|
||||
|
||||
if (isEHB) {
|
||||
if (header.isEHB()) {
|
||||
if (numColors == 32) {
|
||||
reds = Arrays.copyOf(reds, numColors * 2);
|
||||
blues = Arrays.copyOf(blues, numColors * 2);
|
||||
@@ -161,8 +144,10 @@ final class CMAPChunk extends IFFChunk {
|
||||
// Would it work to double to numbers of colors, and create an indexcolormodel,
|
||||
// with alpha, where all colors above the original color is all transparent?
|
||||
// This is a waste of time and space, of course...
|
||||
int transparent = header.maskType == BMHDChunk.MASK_TRANSPARENT_COLOR ? header.transparentIndex : -1;
|
||||
model = new IndexColorModel(header.bitplanes, reds.length, reds, greens, blues, transparent); // https://github.com/haraldk/TwelveMonkeys/issues/15
|
||||
int transparent = header.transparentIndex();
|
||||
int bitplanes = header.bitplanes() == 25 ? 8 : header.bitplanes();
|
||||
|
||||
model = new IndexColorModel(bitplanes, reds.length, reds, greens, blues, transparent); // https://github.com/haraldk/TwelveMonkeys/issues/15
|
||||
}
|
||||
|
||||
return model;
|
||||
|
||||
+2
-2
@@ -38,7 +38,7 @@ package com.twelvemonkeys.imageio.plugins.iff;
|
||||
* @version $Id: CTBLChunk.java,v 1.0 30.03.12 14:53 haraldk Exp$
|
||||
*/
|
||||
final class CTBLChunk extends AbstractMultiPaletteChunk {
|
||||
protected CTBLChunk(int pChunkLength) {
|
||||
super(IFF.CHUNK_CTBL, pChunkLength);
|
||||
CTBLChunk(int chunkLength) {
|
||||
super(IFF.CHUNK_CTBL, chunkLength);
|
||||
}
|
||||
}
|
||||
|
||||
+56
-26
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* Copyright (c) 2022, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -28,45 +28,75 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.cache;
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import com.twelvemonkeys.lang.Validate;
|
||||
import javax.imageio.IIOException;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* AbstractCacheRequest
|
||||
* DGBLChunk
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: AbstractCacheRequest.java#1 $
|
||||
* @version $Id: DGBLChunk.java,v 1.0 28.feb.2006 02:10:07 haku Exp$
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class AbstractCacheRequest implements CacheRequest {
|
||||
private final URI requestURI;
|
||||
private final String method;
|
||||
final class DGBLChunk extends IFFChunk {
|
||||
|
||||
protected AbstractCacheRequest(final URI pRequestURI, final String pMethod) {
|
||||
requestURI = Validate.notNull(pRequestURI, "requestURI");
|
||||
method = Validate.notNull(pMethod, "method");
|
||||
/*
|
||||
//
|
||||
struct DGBL = {
|
||||
//
|
||||
// Size of source display
|
||||
//
|
||||
UWORD DisplayWidth,DisplayHeight;
|
||||
//
|
||||
// Type of compression
|
||||
//
|
||||
UWORD Compression;
|
||||
//
|
||||
// Pixel aspect, a ration w:h
|
||||
//
|
||||
UBYTE xAspect,yAspect;
|
||||
};
|
||||
|
||||
*/
|
||||
int displayWidth;
|
||||
int displayHeight;
|
||||
int compressionType;
|
||||
int xAspect;
|
||||
int yAspect;
|
||||
|
||||
DGBLChunk(int chunkLength) {
|
||||
super(IFF.CHUNK_DGBL, chunkLength);
|
||||
}
|
||||
|
||||
public URI getRequestURI() {
|
||||
return requestURI;
|
||||
@Override
|
||||
void readChunk(final DataInput input) throws IOException {
|
||||
if (chunkLength != 8) {
|
||||
throw new IIOException("Unknown DBGL chunk length: " + chunkLength);
|
||||
}
|
||||
|
||||
displayWidth = input.readUnsignedShort();
|
||||
displayHeight = input.readUnsignedShort();
|
||||
compressionType = input.readUnsignedShort();
|
||||
xAspect = input.readUnsignedByte();
|
||||
yAspect = input.readUnsignedByte();
|
||||
}
|
||||
|
||||
public String getMethod() {
|
||||
return method;
|
||||
@Override
|
||||
void writeChunk(final DataOutput output) {
|
||||
throw new InternalError("Not implemented: writeChunk()");
|
||||
}
|
||||
|
||||
// TODO: Consider overriding equals/hashcode
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder(getClass().getSimpleName())
|
||||
.append("[URI=").append(requestURI)
|
||||
.append(", parameters=").append(getParameters())
|
||||
.append(", headers=").append(getHeaders())
|
||||
.append("]").toString();
|
||||
return super.toString() +
|
||||
"{displayWidth=" + displayWidth +
|
||||
", displayHeight=" + displayHeight +
|
||||
", compression=" + compressionType +
|
||||
", xAspect=" + xAspect +
|
||||
", yAspect=" + yAspect +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
Executable → Regular
+32
-30
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* Copyright (c) 2022, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -28,51 +28,53 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.cache;
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* ServletCacheResponse
|
||||
* DLOCChunk.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: ServletCacheResponse.java#2 $
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: DLOCChunk.java,v 1.0 31/01/2022 haraldk Exp$
|
||||
*/
|
||||
@Deprecated
|
||||
public final class ServletCacheResponse extends AbstractCacheResponse {
|
||||
private HttpServletResponse response;
|
||||
final class DLOCChunk extends IFFChunk {
|
||||
int width;
|
||||
int height;
|
||||
int x;
|
||||
int y;
|
||||
|
||||
public ServletCacheResponse(HttpServletResponse pResponse) {
|
||||
response = pResponse;
|
||||
}
|
||||
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
return response.getOutputStream();
|
||||
DLOCChunk(final int chunkLength) {
|
||||
super(IFF.CHUNK_DLOC, chunkLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStatus(int pStatusCode) {
|
||||
response.setStatus(pStatusCode);
|
||||
super.setStatus(pStatusCode);
|
||||
void readChunk(final DataInput input) throws IOException {
|
||||
if (chunkLength != 8) {
|
||||
throw new IIOException("Unknown DLOC chunk length: " + chunkLength);
|
||||
}
|
||||
|
||||
width = input.readUnsignedShort();
|
||||
height = input.readUnsignedShort();
|
||||
x = input.readShort();
|
||||
y = input.readShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addHeader(String pHeaderName, String pHeaderValue) {
|
||||
response.addHeader(pHeaderName, pHeaderValue);
|
||||
super.addHeader(pHeaderName, pHeaderValue);
|
||||
void writeChunk(final DataOutput output) {
|
||||
throw new InternalError("Not implemented: writeChunk()");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHeader(String pHeaderName, String pHeaderValue) {
|
||||
response.setHeader(pHeaderName, pHeaderValue);
|
||||
super.setHeader(pHeaderName, pHeaderValue);
|
||||
}
|
||||
|
||||
HttpServletResponse getResponse() {
|
||||
return response;
|
||||
public String toString() {
|
||||
return super.toString() +
|
||||
"{width=" + width +
|
||||
", height=" + height +
|
||||
", x=" + x +
|
||||
", y=" + y + '}';
|
||||
}
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* DPELChunk.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: DPELChunk.java,v 1.0 01/02/2022 haraldk Exp$
|
||||
*/
|
||||
final class DPELChunk extends IFFChunk {
|
||||
/*
|
||||
//
|
||||
// Chunk DPEL
|
||||
// ----------
|
||||
struct DPEL = {
|
||||
//
|
||||
// Number of pixel components
|
||||
//
|
||||
ULONG nElements;
|
||||
//
|
||||
// The TypeDepth structure is repeated nElement times to identify
|
||||
// the content of every pixel. Pixels will always be padded to
|
||||
// byte boundaries. The DBOD chunk will be padded to an even
|
||||
// longword boundary.
|
||||
//
|
||||
struct TypeDepth = {
|
||||
//
|
||||
// Type of data
|
||||
//
|
||||
UWORD cType;
|
||||
//
|
||||
// Bit depth of this type
|
||||
//
|
||||
UWORD cBitDepth;
|
||||
} typedepth[Nelements];
|
||||
};
|
||||
*/
|
||||
TypeDepth[] typeDepths;
|
||||
|
||||
DPELChunk(final int chunkLength) {
|
||||
super(IFF.CHUNK_DPEL, chunkLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
void readChunk(final DataInput input) throws IOException {
|
||||
int components = input.readInt(); // Strictly, it's unsigned, but that many components is unlikely...
|
||||
|
||||
if (chunkLength != 4 + components * 4) {
|
||||
throw new IIOException("Unsupported DPEL chunk length: " + chunkLength);
|
||||
}
|
||||
|
||||
typeDepths = new TypeDepth[components];
|
||||
|
||||
for (int i = 0; i < components; i++) {
|
||||
typeDepths[i] = new TypeDepth(input.readUnsignedShort(), input.readUnsignedShort());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void writeChunk(final DataOutput output) {
|
||||
throw new InternalError("Not implemented: writeChunk()");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString()
|
||||
+ "{typeDepths=" + Arrays.toString(typeDepths) + '}';
|
||||
}
|
||||
|
||||
public int bitsPerPixel() {
|
||||
int bitCount = 0;
|
||||
|
||||
for (TypeDepth typeDepth : typeDepths) {
|
||||
bitCount += typeDepth.bitDepth;
|
||||
}
|
||||
|
||||
return bitCount;
|
||||
}
|
||||
|
||||
static class TypeDepth {
|
||||
final int type;
|
||||
final int bitDepth;
|
||||
|
||||
TypeDepth(final int type, final int bitDepth) {
|
||||
this.type = type;
|
||||
this.bitDepth = bitDepth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TypeDepth{" +
|
||||
"type=" + type +
|
||||
", bits=" + bitDepth +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,421 @@
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.IndexColorModel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.twelvemonkeys.imageio.plugins.iff.IFFUtil.toChunkStr;
|
||||
|
||||
/**
|
||||
* Form.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: Form.java,v 1.0 31/01/2022 haraldk Exp$
|
||||
*/
|
||||
abstract class Form {
|
||||
|
||||
final int formType;
|
||||
final List<GenericChunk> meta = new ArrayList<>();
|
||||
|
||||
Form(int formType) {
|
||||
this.formType = formType;
|
||||
}
|
||||
|
||||
abstract int width();
|
||||
abstract int height();
|
||||
abstract float aspect();
|
||||
abstract int bitplanes();
|
||||
abstract int compressionType();
|
||||
|
||||
boolean isMultiPalette() {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean isHAM() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean premultiplied() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int sampleSize() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int transparentIndex() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public IndexColorModel colorMap() throws IIOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ColorModel colorMapForRow(IndexColorModel colorModel, int row) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public abstract boolean hasThumbnail();
|
||||
|
||||
public abstract int thumbnailWidth();
|
||||
|
||||
public abstract int thumbnailHeight();
|
||||
|
||||
public abstract BufferedImage thumbnail();
|
||||
|
||||
abstract long bodyOffset();
|
||||
abstract long bodyLength();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toChunkStr(formType);
|
||||
}
|
||||
|
||||
Form with(final IFFChunk chunk) throws IIOException {
|
||||
if (chunk instanceof GenericChunk) {
|
||||
// TODO: This feels kind of hackish, as it breaks the immutable design, perhaps we should just reconsider...
|
||||
meta.add((GenericChunk) chunk);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(chunk + " not supported in FORM type " + toChunkStr(formType));
|
||||
}
|
||||
|
||||
static Form ofType(int formType) {
|
||||
switch (formType) {
|
||||
case IFF.TYPE_ACBM:
|
||||
case IFF.TYPE_ILBM:
|
||||
case IFF.TYPE_PBM:
|
||||
case IFF.TYPE_RGB8:
|
||||
return new ILBMForm(formType);
|
||||
case IFF.TYPE_DEEP:
|
||||
case IFF.TYPE_TVPP:
|
||||
return new DEEPForm(formType);
|
||||
default:
|
||||
throw new IllegalArgumentException("FORM type " + toChunkStr(formType) + " not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The set of chunks used in the "original" ILBM,
|
||||
* and also ACBM, PBM and RGB8 FORMs.
|
||||
*/
|
||||
static final class ILBMForm extends Form {
|
||||
private final BMHDChunk bitmapHeader;
|
||||
private final CAMGChunk viewMode;
|
||||
private final CMAPChunk colorMap;
|
||||
private final AbstractMultiPaletteChunk multiPalette;
|
||||
private final XS24Chunk thumbnail; // TVPaint puts these into normal IFF ILBM 24 bit files as well as DEEP/TVPP
|
||||
private final BODYChunk body;
|
||||
|
||||
ILBMForm(int formType) {
|
||||
this(formType, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
private ILBMForm(final int formType, final BMHDChunk bitmapHeader, final CAMGChunk viewMode, final CMAPChunk colorMap, final AbstractMultiPaletteChunk multiPalette, final XS24Chunk thumbnail, final BODYChunk body) {
|
||||
super(formType);
|
||||
this.bitmapHeader = bitmapHeader;
|
||||
this.viewMode = viewMode;
|
||||
this.colorMap = colorMap;
|
||||
this.multiPalette = multiPalette;
|
||||
this.thumbnail = thumbnail;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
@Override
|
||||
int width() {
|
||||
return bitmapHeader.width;
|
||||
}
|
||||
|
||||
@Override
|
||||
int height() {
|
||||
return bitmapHeader.height;
|
||||
}
|
||||
|
||||
@Override
|
||||
int bitplanes() {
|
||||
return bitmapHeader.bitplanes;
|
||||
}
|
||||
|
||||
@Override
|
||||
int compressionType() {
|
||||
return bitmapHeader.compressionType;
|
||||
}
|
||||
|
||||
@Override
|
||||
float aspect() {
|
||||
return bitmapHeader.yAspect == 0 ? 0 : (bitmapHeader.xAspect / (float) bitmapHeader.yAspect);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isMultiPalette() {
|
||||
return multiPalette != null;
|
||||
}
|
||||
|
||||
boolean isEHB() {
|
||||
return viewMode != null && viewMode.isEHB();
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isHAM() {
|
||||
return viewMode != null && viewMode.isHAM();
|
||||
}
|
||||
|
||||
boolean isLaced() {
|
||||
return viewMode != null && viewMode.isLaced();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int transparentIndex() {
|
||||
return bitmapHeader.maskType == BMHDChunk.MASK_TRANSPARENT_COLOR ? bitmapHeader.transparentIndex : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IndexColorModel colorMap() throws IIOException {
|
||||
return colorMap != null ? colorMap.getIndexColorModel(this) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ColorModel colorMapForRow(final IndexColorModel colorModel, final int row) {
|
||||
return multiPalette != null ? multiPalette.getColorModel(colorModel, row, isLaced()) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasThumbnail() {
|
||||
return thumbnail != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int thumbnailWidth() {
|
||||
return thumbnail != null ? thumbnail.width : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int thumbnailHeight() {
|
||||
return thumbnail != null ? thumbnail.height : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage thumbnail() {
|
||||
return thumbnail != null ? thumbnail.thumbnail() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
long bodyOffset() {
|
||||
return body.chunkOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
long bodyLength() {
|
||||
return body.chunkLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
ILBMForm with(final IFFChunk chunk) throws IIOException {
|
||||
if (chunk instanceof BMHDChunk) {
|
||||
if (bitmapHeader != null) {
|
||||
throw new IIOException("Multiple BMHD chunks not allowed");
|
||||
}
|
||||
|
||||
return new ILBMForm(formType, (BMHDChunk) chunk, null, colorMap, multiPalette, thumbnail, body);
|
||||
}
|
||||
else if (chunk instanceof CAMGChunk) {
|
||||
if (viewMode != null) {
|
||||
throw new IIOException("Multiple CAMG chunks not allowed");
|
||||
}
|
||||
|
||||
return new ILBMForm(formType, bitmapHeader, (CAMGChunk) chunk, colorMap, multiPalette, thumbnail, body);
|
||||
}
|
||||
else if (chunk instanceof CMAPChunk) {
|
||||
if (colorMap != null) {
|
||||
throw new IIOException("Multiple CMAP chunks not allowed");
|
||||
}
|
||||
|
||||
return new ILBMForm(formType, bitmapHeader, viewMode, (CMAPChunk) chunk, multiPalette, thumbnail, body);
|
||||
}
|
||||
else if (chunk instanceof AbstractMultiPaletteChunk) {
|
||||
// NOTE: We prefer PHCG over SHAM/CTBL style palette changes, if both are present
|
||||
if (multiPalette instanceof PCHGChunk) {
|
||||
if (chunk instanceof PCHGChunk) {
|
||||
throw new IIOException("Multiple PCHG/SHAM/CTBL chunks not allowed");
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
return new ILBMForm(formType, bitmapHeader, viewMode, colorMap, (AbstractMultiPaletteChunk) chunk, thumbnail, body);
|
||||
}
|
||||
else if (chunk instanceof XS24Chunk) {
|
||||
if (thumbnail != null) {
|
||||
throw new IIOException("Multiple XS24 chunks not allowed");
|
||||
}
|
||||
|
||||
return new ILBMForm(formType, bitmapHeader, viewMode, colorMap, multiPalette, (XS24Chunk) chunk, body);
|
||||
}
|
||||
else if (chunk instanceof BODYChunk) {
|
||||
if (body != null) {
|
||||
throw new IIOException("Multiple " + toChunkStr(chunk.chunkId) + " chunks not allowed");
|
||||
}
|
||||
|
||||
return new ILBMForm(formType, bitmapHeader, viewMode, colorMap, multiPalette, thumbnail, (BODYChunk) chunk);
|
||||
}
|
||||
else if (chunk instanceof GRABChunk) {
|
||||
// Ignored for now
|
||||
return this;
|
||||
}
|
||||
|
||||
return (ILBMForm) super.with(chunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + '{' + bitmapHeader +
|
||||
(viewMode != null ? ", " + viewMode : "" ) +
|
||||
(colorMap != null ? ", " + colorMap : "" ) +
|
||||
(multiPalette != null ? ", " + multiPalette : "" ) +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The set of chunks used in DEEP and TVPP FORMs.
|
||||
*/
|
||||
private static final class DEEPForm extends Form {
|
||||
private final DGBLChunk deepGlobal;
|
||||
private final DLOCChunk deepLocation;
|
||||
private final DPELChunk deepPixel;
|
||||
private final XS24Chunk thumbnail;
|
||||
private final BODYChunk body;
|
||||
|
||||
DEEPForm(int formType) {
|
||||
this(formType, null, null, null, null, null);
|
||||
}
|
||||
|
||||
private DEEPForm(final int formType, final DGBLChunk deepGlobal, final DLOCChunk deepLocation, final DPELChunk deepPixel, final XS24Chunk thumbnail, final BODYChunk body) {
|
||||
super(formType);
|
||||
this.deepGlobal = deepGlobal;
|
||||
this.deepLocation = deepLocation;
|
||||
this.deepPixel = deepPixel;
|
||||
this.thumbnail = thumbnail;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
int width() {
|
||||
return deepLocation.width;
|
||||
}
|
||||
|
||||
@Override
|
||||
int height() {
|
||||
return deepLocation.height;
|
||||
}
|
||||
|
||||
@Override
|
||||
int bitplanes() {
|
||||
return deepPixel.bitsPerPixel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int sampleSize() {
|
||||
return bitplanes() / 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean premultiplied() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
int compressionType() {
|
||||
return deepGlobal.compressionType;
|
||||
}
|
||||
|
||||
@Override
|
||||
float aspect() {
|
||||
return deepGlobal.yAspect == 0 ? 0 : deepGlobal.xAspect / (float) deepGlobal.yAspect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasThumbnail() {
|
||||
return thumbnail != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int thumbnailWidth() {
|
||||
return thumbnail != null ? thumbnail.width : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int thumbnailHeight() {
|
||||
return thumbnail != null ? thumbnail.height : -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage thumbnail() {
|
||||
return thumbnail != null ? thumbnail.thumbnail() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
long bodyOffset() {
|
||||
return body.chunkOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
long bodyLength() {
|
||||
return body.chunkLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
DEEPForm with(final IFFChunk chunk) throws IIOException {
|
||||
if (chunk instanceof DGBLChunk) {
|
||||
if (deepGlobal != null) {
|
||||
throw new IIOException("Multiple DGBL chunks not allowed");
|
||||
}
|
||||
|
||||
return new DEEPForm(formType, (DGBLChunk) chunk, null, null, thumbnail, body);
|
||||
}
|
||||
else if (chunk instanceof DLOCChunk) {
|
||||
if (deepLocation != null) {
|
||||
throw new IIOException("Multiple DLOC chunks not allowed");
|
||||
}
|
||||
|
||||
return new DEEPForm(formType, deepGlobal, (DLOCChunk) chunk, deepPixel, thumbnail, body);
|
||||
}
|
||||
else if (chunk instanceof DPELChunk) {
|
||||
if (deepPixel != null) {
|
||||
throw new IIOException("Multiple DPEL chunks not allowed");
|
||||
}
|
||||
|
||||
return new DEEPForm(formType, deepGlobal, deepLocation, (DPELChunk) chunk, thumbnail, body);
|
||||
}
|
||||
else if (chunk instanceof XS24Chunk) {
|
||||
if (thumbnail != null) {
|
||||
throw new IIOException("Multiple XS24 chunks not allowed");
|
||||
}
|
||||
|
||||
return new DEEPForm(formType, deepGlobal, deepLocation, deepPixel, (XS24Chunk) chunk, body);
|
||||
}
|
||||
else if (chunk instanceof BODYChunk) {
|
||||
// TODO: Make a better approach!
|
||||
// if (body != null) {
|
||||
// throw new IIOException("Multiple " + toChunkStr(chunk.chunkId) + " chunks not allowed");
|
||||
// }
|
||||
|
||||
return new DEEPForm(formType, deepGlobal, deepLocation, deepPixel, thumbnail, (BODYChunk) chunk);
|
||||
}
|
||||
|
||||
return (DEEPForm) super.with(chunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + '{' + deepGlobal + ", " + deepLocation + ", " + deepPixel + '}';
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-9
@@ -50,25 +50,25 @@ final class GRABChunk extends IFFChunk {
|
||||
|
||||
Point2D point;
|
||||
|
||||
protected GRABChunk(int pChunkLength) {
|
||||
super(IFF.CHUNK_GRAB, pChunkLength);
|
||||
GRABChunk(int chunkLength) {
|
||||
super(IFF.CHUNK_GRAB, chunkLength);
|
||||
}
|
||||
|
||||
protected GRABChunk(Point2D pPoint) {
|
||||
GRABChunk(Point2D point) {
|
||||
super(IFF.CHUNK_GRAB, 4);
|
||||
point = pPoint;
|
||||
this.point = point;
|
||||
}
|
||||
|
||||
void readChunk(DataInput pInput) throws IOException {
|
||||
void readChunk(DataInput input) throws IOException {
|
||||
if (chunkLength != 4) {
|
||||
throw new IIOException("Unknown GRAB chunk size: " + chunkLength);
|
||||
}
|
||||
point = new Point(pInput.readShort(), pInput.readShort());
|
||||
point = new Point(input.readShort(), input.readShort());
|
||||
}
|
||||
|
||||
void writeChunk(DataOutput pOutput) throws IOException {
|
||||
pOutput.writeShort((int) point.getX());
|
||||
pOutput.writeShort((int) point.getY());
|
||||
void writeChunk(DataOutput output) throws IOException {
|
||||
output.writeShort((int) point.getX());
|
||||
output.writeShort((int) point.getY());
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
|
||||
+14
-14
@@ -44,31 +44,31 @@ final class GenericChunk extends IFFChunk {
|
||||
|
||||
byte[] data;
|
||||
|
||||
protected GenericChunk(int pChunkId, int pChunkLength) {
|
||||
super(pChunkId, pChunkLength);
|
||||
data = new byte[chunkLength];
|
||||
GenericChunk(int chunkId, int chunkLength) {
|
||||
super(chunkId, chunkLength);
|
||||
data = new byte[this.chunkLength];
|
||||
}
|
||||
|
||||
protected GenericChunk(int pChunkId, byte[] pChunkData) {
|
||||
super(pChunkId, pChunkData.length);
|
||||
data = pChunkData;
|
||||
GenericChunk(int chunkId, byte[] chunkData) {
|
||||
super(chunkId, chunkData.length);
|
||||
data = chunkData;
|
||||
}
|
||||
|
||||
@Override
|
||||
void readChunk(final DataInput pInput) throws IOException {
|
||||
pInput.readFully(data, 0, data.length);
|
||||
void readChunk(final DataInput input) throws IOException {
|
||||
input.readFully(data, 0, data.length);
|
||||
|
||||
skipData(pInput, chunkLength, data.length);
|
||||
skipData(input, chunkLength, data.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
void writeChunk(final DataOutput pOutput) throws IOException {
|
||||
pOutput.writeInt(chunkId);
|
||||
pOutput.writeInt(chunkLength);
|
||||
pOutput.write(data, 0, data.length);
|
||||
void writeChunk(final DataOutput output) throws IOException {
|
||||
output.writeInt(chunkId);
|
||||
output.writeInt(chunkLength);
|
||||
output.write(data, 0, data.length);
|
||||
|
||||
if (data.length % 2 != 0) {
|
||||
pOutput.writeByte(0); // PAD
|
||||
output.writeByte(0); // PAD
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,8 @@ interface IFF {
|
||||
// TODO:
|
||||
/** IFF DEEP form type (TVPaint) */
|
||||
int TYPE_DEEP = ('D' << 24) + ('E' << 16) + ('E' << 8) + 'P';
|
||||
/** IFF TVPP form type (TVPaint Project) */
|
||||
int TYPE_TVPP = ('T' << 24) + ('V' << 16) + ('P' << 8) + 'P';
|
||||
/** IFF RGB8 form type (TurboSilver) */
|
||||
int TYPE_RGB8 = ('R' << 24) + ('G' << 16) + ('B' << 8) + '8';
|
||||
/** IFF RGBN form type (TurboSilver) */
|
||||
@@ -92,7 +94,7 @@ interface IFF {
|
||||
int CHUNK_COPY = ('(' << 24) + ('c' << 16) + (')' << 8) + ' ';
|
||||
|
||||
/** EA IFF 85 Generic annotation chunk (usually used for Software) */
|
||||
int CHUNK_ANNO = ('A' << 24) + ('N' << 16) + ('N' << 8) + 'O';;
|
||||
int CHUNK_ANNO = ('A' << 24) + ('N' << 16) + ('N' << 8) + 'O';
|
||||
|
||||
/** Third-party defined UTF-8 text. */
|
||||
int CHUNK_UTF8 = ('U' << 24) + ('T' << 16) + ('F' << 8) + '8';
|
||||
@@ -129,6 +131,18 @@ interface IFF {
|
||||
int CHUNK_SHAM = ('S' << 24) + ('H' << 16) + ('A' << 8) + 'M';
|
||||
/** ACBM body chunk */
|
||||
int CHUNK_ABIT = ('A' << 24) + ('B' << 16) + ('I' << 8) + 'T';
|
||||
/** unofficial direct color */
|
||||
/** Unofficial direct color */
|
||||
int CHUNK_DCOL = ('D' << 24) + ('C' << 16) + ('O' << 8) + 'L';
|
||||
/** TVPaint Deep GloBaL information */
|
||||
int CHUNK_DGBL = ('D' << 24) + ('G' << 16) + ('B' << 8) + 'L';
|
||||
/** TVPaint Deep Pixel ELements */
|
||||
int CHUNK_DPEL = ('D' << 24) + ('P' << 16) + ('E' << 8) + 'L';
|
||||
/** TVPaint Deep LOCation information */
|
||||
int CHUNK_DLOC = ('D' << 24) + ('L' << 16) + ('O' << 8) + 'C';
|
||||
/** TVPaint Deep BODy */
|
||||
int CHUNK_DBOD = ('D' << 24) + ('B' << 16) + ('O' << 8) + 'D';
|
||||
/** TVPaint Deep CHanGe buffer */
|
||||
int CHUNK_DCHG = ('D' << 24) + ('C' << 16) + ('H' << 8) + 'G';
|
||||
/** TVPaint 24 bit thumbnail */
|
||||
int CHUNK_XS24 = ('X' << 24) + ('S' << 16) + ('2' << 8) + '4';
|
||||
}
|
||||
|
||||
+8
-8
@@ -44,25 +44,25 @@ abstract class IFFChunk {
|
||||
int chunkId;
|
||||
int chunkLength;
|
||||
|
||||
protected IFFChunk(int pChunkId, int pChunkLength) {
|
||||
chunkId = pChunkId;
|
||||
chunkLength = pChunkLength;
|
||||
protected IFFChunk(int chunkId, int chunkLength) {
|
||||
this.chunkId = chunkId;
|
||||
this.chunkLength = chunkLength;
|
||||
}
|
||||
|
||||
abstract void readChunk(DataInput pInput) throws IOException;
|
||||
abstract void readChunk(DataInput input) throws IOException;
|
||||
|
||||
abstract void writeChunk(DataOutput pOutput) throws IOException;
|
||||
abstract void writeChunk(DataOutput output) throws IOException;
|
||||
|
||||
protected static void skipData(final DataInput pInput, final int chunkLength, final int dataReadSoFar) throws IOException {
|
||||
protected static void skipData(final DataInput input, final int chunkLength, final int dataReadSoFar) throws IOException {
|
||||
int toSkip = chunkLength - dataReadSoFar;
|
||||
|
||||
while (toSkip > 0) {
|
||||
toSkip -= pInput.skipBytes(toSkip);
|
||||
toSkip -= input.skipBytes(toSkip);
|
||||
}
|
||||
|
||||
// Read pad
|
||||
if (chunkLength % 2 != 0) {
|
||||
pInput.readByte();
|
||||
input.readByte();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+38
-25
@@ -13,31 +13,29 @@ import static com.twelvemonkeys.lang.Validate.isTrue;
|
||||
import static com.twelvemonkeys.lang.Validate.notNull;
|
||||
|
||||
final class IFFImageMetadata extends AbstractMetadata {
|
||||
private final int formType;
|
||||
private final BMHDChunk header;
|
||||
private final Form header;
|
||||
private final IndexColorModel colorMap;
|
||||
private final CAMGChunk viewPort;
|
||||
private final List<GenericChunk> meta;
|
||||
|
||||
IFFImageMetadata(int formType, BMHDChunk header, IndexColorModel colorMap, CAMGChunk viewPort, List<GenericChunk> meta) {
|
||||
this.formType = isTrue(validFormType(formType), formType, "Unknown IFF Form type: %s");
|
||||
IFFImageMetadata(Form header, IndexColorModel colorMap) {
|
||||
this.header = notNull(header, "header");
|
||||
isTrue(validFormType(header.formType), header.formType, "Unknown IFF Form type: %s");
|
||||
this.colorMap = colorMap;
|
||||
this.viewPort = viewPort;
|
||||
this.meta = meta;
|
||||
this.meta = header.meta;
|
||||
}
|
||||
|
||||
private boolean validFormType(int formType) {
|
||||
switch (formType) {
|
||||
default:
|
||||
return false;
|
||||
case TYPE_ACBM:
|
||||
case TYPE_DEEP:
|
||||
case TYPE_ILBM:
|
||||
case TYPE_PBM:
|
||||
case TYPE_RGB8:
|
||||
case TYPE_RGBN:
|
||||
case TYPE_TVPP:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +46,7 @@ final class IFFImageMetadata extends AbstractMetadata {
|
||||
IIOMetadataNode csType = new IIOMetadataNode("ColorSpaceType");
|
||||
chroma.appendChild(csType);
|
||||
|
||||
switch (header.bitplanes) {
|
||||
switch (header.bitplanes()) {
|
||||
case 8:
|
||||
if (colorMap == null) {
|
||||
csType.setAttribute("name", "GRAY");
|
||||
@@ -62,6 +60,7 @@ final class IFFImageMetadata extends AbstractMetadata {
|
||||
case 6:
|
||||
case 7:
|
||||
case 24:
|
||||
case 25:
|
||||
case 32:
|
||||
csType.setAttribute("name", "RGB");
|
||||
break;
|
||||
@@ -72,10 +71,10 @@ final class IFFImageMetadata extends AbstractMetadata {
|
||||
// NOTE: Channels in chroma node reflects channels in color model (see data node, for channels in data)
|
||||
IIOMetadataNode numChannels = new IIOMetadataNode("NumChannels");
|
||||
chroma.appendChild(numChannels);
|
||||
if (colorMap == null && header.bitplanes == 8) {
|
||||
if (colorMap == null && header.bitplanes() == 8) {
|
||||
numChannels.setAttribute("value", Integer.toString(1));
|
||||
}
|
||||
else if (header.bitplanes == 32) {
|
||||
else if (header.bitplanes() == 25 || header.bitplanes() == 32) {
|
||||
numChannels.setAttribute("value", Integer.toString(4));
|
||||
}
|
||||
else {
|
||||
@@ -102,9 +101,16 @@ final class IFFImageMetadata extends AbstractMetadata {
|
||||
paletteEntry.setAttribute("green", Integer.toString(colorMap.getGreen(i)));
|
||||
paletteEntry.setAttribute("blue", Integer.toString(colorMap.getBlue(i)));
|
||||
}
|
||||
|
||||
if (colorMap.getTransparentPixel() != -1) {
|
||||
IIOMetadataNode backgroundIndex = new IIOMetadataNode("BackgroundIndex");
|
||||
chroma.appendChild(backgroundIndex);
|
||||
backgroundIndex.setAttribute("value", Integer.toString(colorMap.getTransparentPixel()));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Background color is the color of the transparent index in the color model?
|
||||
// TODO: TVPP TVPaint Project files have a MIXR chunk with a background color
|
||||
// and also a BGP1 (background pen 1?) and BGP2 chunks
|
||||
// if (extensions != null && extensions.getBackgroundColor() != 0) {
|
||||
// Color background = new Color(extensions.getBackgroundColor(), true);
|
||||
//
|
||||
@@ -121,7 +127,7 @@ final class IFFImageMetadata extends AbstractMetadata {
|
||||
|
||||
@Override
|
||||
protected IIOMetadataNode getStandardCompressionNode() {
|
||||
if (header.compressionType == BMHDChunk.COMPRESSION_NONE) {
|
||||
if (header.compressionType() == BMHDChunk.COMPRESSION_NONE) {
|
||||
return null; // All defaults
|
||||
}
|
||||
|
||||
@@ -144,7 +150,10 @@ final class IFFImageMetadata extends AbstractMetadata {
|
||||
|
||||
// PlanarConfiguration
|
||||
IIOMetadataNode planarConfiguration = new IIOMetadataNode("PlanarConfiguration");
|
||||
switch (formType) {
|
||||
switch (header.formType) {
|
||||
case TYPE_DEEP:
|
||||
case TYPE_TVPP:
|
||||
case TYPE_RGB8:
|
||||
case TYPE_PBM:
|
||||
planarConfiguration.setAttribute("value", "PixelInterleaved");
|
||||
break;
|
||||
@@ -152,7 +161,7 @@ final class IFFImageMetadata extends AbstractMetadata {
|
||||
planarConfiguration.setAttribute("value", "PlaneInterleaved");
|
||||
break;
|
||||
default:
|
||||
planarConfiguration.setAttribute("value", "Unknown " + IFFUtil.toChunkStr(formType));
|
||||
planarConfiguration.setAttribute("value", "Unknown " + IFFUtil.toChunkStr(header.formType));
|
||||
break;
|
||||
}
|
||||
data.appendChild(planarConfiguration);
|
||||
@@ -163,7 +172,7 @@ final class IFFImageMetadata extends AbstractMetadata {
|
||||
|
||||
// BitsPerSample
|
||||
IIOMetadataNode bitsPerSample = new IIOMetadataNode("BitsPerSample");
|
||||
String value = bitsPerSampleValue(header.bitplanes);
|
||||
String value = bitsPerSampleValue(header.bitplanes());
|
||||
bitsPerSample.setAttribute("value", value);
|
||||
data.appendChild(bitsPerSample);
|
||||
|
||||
@@ -171,7 +180,6 @@ final class IFFImageMetadata extends AbstractMetadata {
|
||||
// SampleMSB not in format
|
||||
|
||||
return data;
|
||||
|
||||
}
|
||||
|
||||
private String bitsPerSampleValue(int bitplanes) {
|
||||
@@ -187,16 +195,22 @@ final class IFFImageMetadata extends AbstractMetadata {
|
||||
return Integer.toString(bitplanes);
|
||||
case 24:
|
||||
return "8 8 8";
|
||||
case 25:
|
||||
if (header.formType != TYPE_RGB8) {
|
||||
throw new IllegalArgumentException(String.format("25 bit depth only supported for FORM type RGB8: %s", IFFUtil.toChunkStr(header.formType)));
|
||||
}
|
||||
|
||||
return "8 8 8 1";
|
||||
case 32:
|
||||
return "8 8 8 8";
|
||||
default:
|
||||
throw new IllegalArgumentException("Ubknown bit count: " + bitplanes);
|
||||
throw new IllegalArgumentException("Unknown bit count: " + bitplanes);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IIOMetadataNode getStandardDimensionNode() {
|
||||
if (viewPort == null) {
|
||||
if (header.aspect() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -204,7 +218,7 @@ final class IFFImageMetadata extends AbstractMetadata {
|
||||
|
||||
// PixelAspectRatio
|
||||
IIOMetadataNode pixelAspectRatio = new IIOMetadataNode("PixelAspectRatio");
|
||||
pixelAspectRatio.setAttribute("value", String.valueOf((viewPort.isHires() ? 2f : 1f) / (viewPort.isLaced() ? 2f : 1f)));
|
||||
pixelAspectRatio.setAttribute("value", String.valueOf(header.aspect()));
|
||||
dimension.appendChild(pixelAspectRatio);
|
||||
|
||||
// TODO: HorizontalScreenSize?
|
||||
@@ -241,20 +255,19 @@ final class IFFImageMetadata extends AbstractMetadata {
|
||||
}
|
||||
|
||||
return text;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IIOMetadataNode getStandardTransparencyNode() {
|
||||
if ((colorMap == null || !colorMap.hasAlpha()) && header.bitplanes != 32) {
|
||||
if ((colorMap == null || !colorMap.hasAlpha()) && header.bitplanes() != 32 && header.bitplanes() != 25) {
|
||||
return null;
|
||||
}
|
||||
|
||||
IIOMetadataNode transparency = new IIOMetadataNode("Transparency");
|
||||
|
||||
if (header.bitplanes == 32) {
|
||||
if (header.bitplanes() == 25 || header.bitplanes() == 32) {
|
||||
IIOMetadataNode alpha = new IIOMetadataNode("Alpha");
|
||||
alpha.setAttribute("value", "nonpremultiplied");
|
||||
alpha.setAttribute("value", header.premultiplied() ? "premultiplied" : "nonpremultiplied");
|
||||
transparency.appendChild(alpha);
|
||||
}
|
||||
|
||||
|
||||
+378
-295
File diff suppressed because it is too large
Load Diff
+16
-17
@@ -30,13 +30,12 @@
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import com.twelvemonkeys.imageio.spi.ImageReaderSpiBase;
|
||||
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
|
||||
import com.twelvemonkeys.imageio.spi.ImageReaderSpiBase;
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* IFFImageReaderSpi
|
||||
@@ -54,41 +53,41 @@ public final class IFFImageReaderSpi extends ImageReaderSpiBase {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDecodeInput(Object pSource) throws IOException {
|
||||
return pSource instanceof ImageInputStream && canDecode((ImageInputStream) pSource);
|
||||
public boolean canDecodeInput(final Object source) throws IOException {
|
||||
return source instanceof ImageInputStream && canDecode((ImageInputStream) source);
|
||||
}
|
||||
|
||||
private static boolean canDecode(ImageInputStream pInput) throws IOException {
|
||||
pInput.mark();
|
||||
private static boolean canDecode(final ImageInputStream input) throws IOException {
|
||||
input.mark();
|
||||
|
||||
try {
|
||||
// Is it IFF
|
||||
if (pInput.readInt() == IFF.CHUNK_FORM) {
|
||||
pInput.readInt();// Skip length field
|
||||
if (input.readInt() == IFF.CHUNK_FORM) {
|
||||
input.readInt();// Skip length field
|
||||
|
||||
int type = pInput.readInt();
|
||||
|
||||
// Is it ILBM or PBM
|
||||
if (type == IFF.TYPE_ILBM || type == IFF.TYPE_PBM) {
|
||||
int type = input.readInt();
|
||||
if (type == IFF.TYPE_ILBM || type == IFF.TYPE_PBM
|
||||
|| type == IFF.TYPE_RGB8 // Impulse RGB8 format
|
||||
|| type == IFF.TYPE_DEEP || type == IFF.TYPE_TVPP) { // TVPaint DEEP format
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
finally {
|
||||
pInput.reset();
|
||||
input.reset();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageReader createReaderInstance(Object pExtension) throws IOException {
|
||||
public ImageReader createReaderInstance(final Object extension) {
|
||||
return new IFFImageReader(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription(Locale pLocale) {
|
||||
public String getDescription(Locale locale) {
|
||||
return "Commodore Amiga/Electronic Arts Image Interchange Format (IFF) image reader";
|
||||
}
|
||||
}
|
||||
|
||||
+57
-60
@@ -30,31 +30,22 @@
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.IndexColorModel;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import javax.imageio.IIOImage;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.ImageWriteParam;
|
||||
import javax.imageio.ImageWriter;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.spi.ImageWriterSpi;
|
||||
|
||||
import com.twelvemonkeys.imageio.ImageWriterBase;
|
||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||
import com.twelvemonkeys.io.FastByteArrayOutputStream;
|
||||
import com.twelvemonkeys.io.enc.EncoderStream;
|
||||
import com.twelvemonkeys.io.enc.PackBitsEncoder;
|
||||
|
||||
import javax.imageio.*;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.spi.ImageWriterSpi;
|
||||
import java.awt.*;
|
||||
import java.awt.image.*;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Writer for Commodore Amiga (Electronic Arts) IFF ILBM (InterLeaved BitMap) format.
|
||||
* The IFF format (Interchange File Format) is the standard file format
|
||||
@@ -68,8 +59,8 @@ import com.twelvemonkeys.io.enc.PackBitsEncoder;
|
||||
*/
|
||||
public final class IFFImageWriter extends ImageWriterBase {
|
||||
|
||||
IFFImageWriter(ImageWriterSpi pProvider) {
|
||||
super(pProvider);
|
||||
IFFImageWriter(ImageWriterSpi provider) {
|
||||
super(provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -83,23 +74,29 @@ public final class IFFImageWriter extends ImageWriterBase {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(IIOMetadata pStreamMetadata, IIOImage pImage, ImageWriteParam pParam) throws IOException {
|
||||
public ImageWriteParam getDefaultWriteParam() {
|
||||
return new IFFWriteParam(getLocale());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(IIOMetadata streamMetadata, IIOImage image, ImageWriteParam param) throws IOException {
|
||||
assertOutput();
|
||||
|
||||
if (pImage.hasRaster()) {
|
||||
if (image.hasRaster()) {
|
||||
throw new UnsupportedOperationException("Cannot write raster");
|
||||
}
|
||||
|
||||
processImageStarted(0);
|
||||
|
||||
RenderedImage renderedImage = image.getRenderedImage();
|
||||
boolean compress = shouldCompress(renderedImage, param);
|
||||
|
||||
// Prepare image data to be written
|
||||
ByteArrayOutputStream imageData = new FastByteArrayOutputStream(1024);
|
||||
packImageData(imageData, pImage.getRenderedImage(), pParam);
|
||||
|
||||
//System.out.println("Image data: " + imageData.size());
|
||||
packImageData(imageData, renderedImage, compress);
|
||||
|
||||
// Write metadata
|
||||
writeMeta(pImage.getRenderedImage(), imageData.size());
|
||||
writeMeta(renderedImage, imageData.size(), compress);
|
||||
|
||||
// Write image data
|
||||
writeBody(imageData);
|
||||
@@ -107,34 +104,31 @@ public final class IFFImageWriter extends ImageWriterBase {
|
||||
processImageComplete();
|
||||
}
|
||||
|
||||
private void writeBody(ByteArrayOutputStream pImageData) throws IOException {
|
||||
private void writeBody(ByteArrayOutputStream imageData) throws IOException {
|
||||
imageOutput.writeInt(IFF.CHUNK_BODY);
|
||||
imageOutput.writeInt(pImageData.size());
|
||||
imageOutput.writeInt(imageData.size());
|
||||
|
||||
// NOTE: This is much faster than imageOutput.write(pImageData.toByteArray())
|
||||
// NOTE: This is much faster than imageOutput.write(imageData.toByteArray())
|
||||
// as the data array is not duplicated
|
||||
try (OutputStream adapter = IIOUtil.createStreamAdapter(imageOutput)) {
|
||||
pImageData.writeTo(adapter);
|
||||
imageData.writeTo(adapter);
|
||||
}
|
||||
|
||||
if (pImageData.size() % 2 == 0) {
|
||||
if (imageData.size() % 2 == 0) {
|
||||
imageOutput.writeByte(0); // PAD
|
||||
}
|
||||
|
||||
imageOutput.flush();
|
||||
}
|
||||
|
||||
private void packImageData(OutputStream pOutput, RenderedImage pImage, ImageWriteParam pParam) throws IOException {
|
||||
// TODO: Allow param to dictate uncompressed
|
||||
// TODO: Allow param to dictate type PBM?
|
||||
private void packImageData(OutputStream outputStream, RenderedImage image, final boolean compress) throws IOException {
|
||||
// TODO: Subsample/AOI
|
||||
final boolean compress = shouldCompress(pImage);
|
||||
final OutputStream output = compress ? new EncoderStream(pOutput, new PackBitsEncoder(), true) : pOutput;
|
||||
final ColorModel model = pImage.getColorModel();
|
||||
final Raster raster = pImage.getData();
|
||||
final OutputStream output = compress ? new EncoderStream(outputStream, new PackBitsEncoder(), true) : outputStream;
|
||||
final ColorModel model = image.getColorModel();
|
||||
final Raster raster = image.getData();
|
||||
|
||||
final int width = pImage.getWidth();
|
||||
final int height = pImage.getHeight();
|
||||
final int width = image.getWidth();
|
||||
final int height = image.getHeight();
|
||||
|
||||
// Store each row of pixels
|
||||
// 0. Loop pr channel
|
||||
@@ -142,7 +136,6 @@ public final class IFFImageWriter extends ImageWriterBase {
|
||||
// 2. Perform byteRun1 compression for each plane separately
|
||||
// 3. Write the plane data for each plane
|
||||
|
||||
//final int planeWidth = (width + 7) / 8;
|
||||
final int planeWidth = 2 * ((width + 15) / 16);
|
||||
final byte[] planeData = new byte[8 * planeWidth];
|
||||
final int channels = (model.getPixelSize() + 7) / 8;
|
||||
@@ -167,10 +160,6 @@ public final class IFFImageWriter extends ImageWriterBase {
|
||||
|
||||
for (int p = 0; p < planesPerChannel; p++) {
|
||||
output.write(planeData, p * planeWidth, planeWidth);
|
||||
|
||||
if (!compress && planeWidth % 2 != 0) {
|
||||
output.write(0); // PAD
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,17 +171,16 @@ public final class IFFImageWriter extends ImageWriterBase {
|
||||
output.flush();
|
||||
}
|
||||
|
||||
private void writeMeta(RenderedImage pImage, int pBodyLength) throws IOException {
|
||||
private void writeMeta(RenderedImage image, int bodyLength, boolean compress) throws IOException {
|
||||
// Annotation ANNO chunk, 8 + annoData.length bytes
|
||||
String annotation = String.format("Written by %s IFFImageWriter %s", getOriginatingProvider().getVendorName(), getOriginatingProvider().getVersion());
|
||||
GenericChunk anno = new GenericChunk(IFFUtil.toInt("ANNO".getBytes()), annotation.getBytes());
|
||||
|
||||
ColorModel cm = pImage.getColorModel();
|
||||
ColorModel cm = image.getColorModel();
|
||||
IndexColorModel icm = null;
|
||||
|
||||
// Bitmap header BMHD chunk, 8 + 20 bytes
|
||||
// By default, don't compress narrow images
|
||||
int compression = shouldCompress(pImage) ? BMHDChunk.COMPRESSION_BYTE_RUN : BMHDChunk.COMPRESSION_NONE;
|
||||
int compression = compress ? BMHDChunk.COMPRESSION_BYTE_RUN : BMHDChunk.COMPRESSION_NONE;
|
||||
|
||||
BMHDChunk header;
|
||||
if (cm instanceof IndexColorModel) {
|
||||
@@ -200,12 +188,12 @@ public final class IFFImageWriter extends ImageWriterBase {
|
||||
icm = (IndexColorModel) cm;
|
||||
int trans = icm.getTransparency() == Transparency.BITMASK ? BMHDChunk.MASK_TRANSPARENT_COLOR : BMHDChunk.MASK_NONE;
|
||||
int transPixel = icm.getTransparency() == Transparency.BITMASK ? icm.getTransparentPixel() : 0;
|
||||
header = new BMHDChunk(pImage.getWidth(), pImage.getHeight(), icm.getPixelSize(),
|
||||
header = new BMHDChunk(image.getWidth(), image.getHeight(), icm.getPixelSize(),
|
||||
trans, compression, transPixel);
|
||||
}
|
||||
else {
|
||||
//System.out.println(cm.getClass().getName());
|
||||
header = new BMHDChunk(pImage.getWidth(), pImage.getHeight(), cm.getPixelSize(),
|
||||
header = new BMHDChunk(image.getWidth(), image.getHeight(), cm.getPixelSize(),
|
||||
BMHDChunk.MASK_NONE, compression, 0);
|
||||
}
|
||||
|
||||
@@ -217,7 +205,7 @@ public final class IFFImageWriter extends ImageWriterBase {
|
||||
}
|
||||
|
||||
// ILBM(4) + anno(8+len) + header(8+20) + cmap(8+len)? + body(8+len);
|
||||
int size = 4 + 8 + anno.chunkLength + 28 + 8 + pBodyLength;
|
||||
int size = 4 + 8 + anno.chunkLength + 28 + 8 + bodyLength;
|
||||
if (cmap != null) {
|
||||
size += 8 + cmap.chunkLength;
|
||||
}
|
||||
@@ -231,21 +219,30 @@ public final class IFFImageWriter extends ImageWriterBase {
|
||||
header.writeChunk(imageOutput);
|
||||
|
||||
if (cmap != null) {
|
||||
//System.out.println("CMAP written");
|
||||
cmap.writeChunk(imageOutput);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean shouldCompress(RenderedImage pImage) {
|
||||
return pImage.getWidth() >= 32;
|
||||
private boolean shouldCompress(final RenderedImage image, final ImageWriteParam param) {
|
||||
if (param != null && param.canWriteCompressed()) {
|
||||
switch (param.getCompressionMode()) {
|
||||
case ImageWriteParam.MODE_DISABLED:
|
||||
return false;
|
||||
case ImageWriteParam.MODE_EXPLICIT:
|
||||
return IFFWriteParam.COMPRESSION_TYPES[1].equals(param.getCompressionType());
|
||||
default:
|
||||
// Fall through
|
||||
}
|
||||
}
|
||||
|
||||
return image.getWidth() >= 32;
|
||||
}
|
||||
|
||||
public static void main(String[] pArgs) throws IOException {
|
||||
BufferedImage image = ImageIO.read(new File(pArgs[0]));
|
||||
public static void main(String[] args) throws IOException {
|
||||
BufferedImage image = ImageIO.read(new File(args[0]));
|
||||
|
||||
ImageWriter writer = new IFFImageWriter(new IFFImageWriterSpi());
|
||||
writer.setOutput(ImageIO.createImageOutputStream(new File(pArgs[1])));
|
||||
writer.setOutput(ImageIO.createImageOutputStream(new File(args[1])));
|
||||
//writer.addIIOWriteProgressListener(new ProgressListenerBase() {
|
||||
// int mCurrPct = 0;
|
||||
//
|
||||
|
||||
+5
-7
@@ -30,13 +30,11 @@
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import com.twelvemonkeys.imageio.spi.ImageWriterSpiBase;
|
||||
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.ImageWriter;
|
||||
|
||||
import com.twelvemonkeys.imageio.spi.ImageWriterSpiBase;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* IFFImageWriterSpi
|
||||
@@ -53,19 +51,19 @@ public class IFFImageWriterSpi extends ImageWriterSpiBase {
|
||||
super(new IFFProviderInfo());
|
||||
}
|
||||
|
||||
public boolean canEncodeImage(final ImageTypeSpecifier pType) {
|
||||
public boolean canEncodeImage(final ImageTypeSpecifier type) {
|
||||
// TODO: Probably can't store 16 bit types etc...
|
||||
// TODO: Can't store CMYK (well.. it does, but they can't be read back)
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageWriter createWriterInstance(Object pExtension) throws IOException {
|
||||
public ImageWriter createWriterInstance(Object extension) {
|
||||
return new IFFImageWriter(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription(Locale pLocale) {
|
||||
public String getDescription(Locale locale) {
|
||||
return "Commodore Amiga/Electronic Arts Image Interchange Format (IFF) image writer";
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -40,11 +40,11 @@ import com.twelvemonkeys.imageio.spi.ReaderWriterProviderInfo;
|
||||
* @version $Id: IFFProviderInfo.java,v 1.0 20/03/15 harald.kuhr Exp$
|
||||
*/
|
||||
final class IFFProviderInfo extends ReaderWriterProviderInfo {
|
||||
protected IFFProviderInfo() {
|
||||
IFFProviderInfo() {
|
||||
super(
|
||||
IFFProviderInfo.class,
|
||||
new String[] {"iff", "IFF"},
|
||||
new String[] {"iff", "lbm", "ham", "ham8", "ilbm"},
|
||||
new String[] {"iff", "lbm", "ham", "ham8", "ilbm", "rgb8", "deep"},
|
||||
new String[] {"image/iff", "image/x-iff"},
|
||||
"com.twelvemonkeys.imageio.plugins.iff.IFFImageReader",
|
||||
new String[]{"com.twelvemonkeys.imageio.plugins.iff.IFFImageReaderSpi"},
|
||||
|
||||
+107
-106
@@ -56,11 +56,11 @@ final class IFFUtil {
|
||||
* @return the rotation table
|
||||
*/
|
||||
static private long[] rtable(int n) {
|
||||
return new long[]{
|
||||
0x00000000l << n, 0x00000001l << n, 0x00000100l << n, 0x00000101l << n,
|
||||
0x00010000l << n, 0x00010001l << n, 0x00010100l << n, 0x00010101l << n,
|
||||
0x01000000l << n, 0x01000001l << n, 0x01000100l << n, 0x01000101l << n,
|
||||
0x01010000l << n, 0x01010001l << n, 0x01010100l << n, 0x01010101l << n
|
||||
return new long[] {
|
||||
0x00000000L , 0x00000001L << n, 0x00000100L << n, 0x00000101L << n,
|
||||
0x00010000L << n, 0x00010001L << n, 0x00010100L << n, 0x00010101L << n,
|
||||
0x01000000L << n, 0x01000001L << n, 0x01000100L << n, 0x01000101L << n,
|
||||
0x01010000L << n, 0x01010001L << n, 0x01010100L << n, 0x01010101L << n
|
||||
};
|
||||
}
|
||||
|
||||
@@ -75,16 +75,16 @@ final class IFFUtil {
|
||||
* Bits from the source are rotated 90 degrees clockwise written to the
|
||||
* destination.
|
||||
*
|
||||
* @param pSrc source pixel data
|
||||
* @param pSrcPos starting index of 8 x 8 bit source tile
|
||||
* @param pSrcStep byte offset between adjacent rows in source
|
||||
* @param pDst destination pixel data
|
||||
* @param pDstPos starting index of 8 x 8 bit destination tile
|
||||
* @param pDstStep byte offset between adjacent rows in destination
|
||||
* @param src source pixel data
|
||||
* @param srcPos starting index of 8 x 8 bit source tile
|
||||
* @param srcStep byte offset between adjacent rows in source
|
||||
* @param dst destination pixel data
|
||||
* @param dstPos starting index of 8 x 8 bit destination tile
|
||||
* @param dstStep byte offset between adjacent rows in destination
|
||||
*/
|
||||
static void bitRotateCW(final byte[] pSrc, int pSrcPos, int pSrcStep,
|
||||
final byte[] pDst, int pDstPos, int pDstStep) {
|
||||
int idx = pSrcPos;
|
||||
static void bitRotateCW(final byte[] src, int srcPos, int srcStep,
|
||||
final byte[] dst, int dstPos, int dstStep) {
|
||||
int idx = srcPos;
|
||||
|
||||
int lonyb;
|
||||
int hinyb;
|
||||
@@ -92,41 +92,41 @@ final class IFFUtil {
|
||||
long hi = 0;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
lonyb = pSrc[idx] & 0xF;
|
||||
hinyb = (pSrc[idx] >> 4) & 0xF;
|
||||
lonyb = src[idx] & 0xF;
|
||||
hinyb = (src[idx] >> 4) & 0xF;
|
||||
lo |= RTABLE[i][lonyb];
|
||||
hi |= RTABLE[i][hinyb];
|
||||
idx += pSrcStep;
|
||||
idx += srcStep;
|
||||
}
|
||||
|
||||
idx = pDstPos;
|
||||
idx = dstPos;
|
||||
|
||||
pDst[idx] = (byte)((hi >> 24) & 0xFF);
|
||||
idx += pDstStep;
|
||||
if (idx < pDst.length) {
|
||||
pDst[idx] = (byte)((hi >> 16) & 0xFF);
|
||||
idx += pDstStep;
|
||||
if (idx < pDst.length) {
|
||||
pDst[idx] = (byte)((hi >> 8) & 0xFF);
|
||||
idx += pDstStep;
|
||||
if (idx < pDst.length) {
|
||||
pDst[idx] = (byte)(hi & 0xFF);
|
||||
idx += pDstStep;
|
||||
dst[idx] = (byte)((hi >> 24) & 0xFF);
|
||||
idx += dstStep;
|
||||
if (idx < dst.length) {
|
||||
dst[idx] = (byte)((hi >> 16) & 0xFF);
|
||||
idx += dstStep;
|
||||
if (idx < dst.length) {
|
||||
dst[idx] = (byte)((hi >> 8) & 0xFF);
|
||||
idx += dstStep;
|
||||
if (idx < dst.length) {
|
||||
dst[idx] = (byte)(hi & 0xFF);
|
||||
idx += dstStep;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (idx < pDst.length) {
|
||||
pDst[idx] = (byte)((lo >> 24) & 0xFF);
|
||||
idx += pDstStep;
|
||||
if (idx < pDst.length) {
|
||||
pDst[idx] = (byte)((lo >> 16) & 0xFF);
|
||||
idx += pDstStep;
|
||||
if (idx < pDst.length) {
|
||||
pDst[idx] = (byte)((lo >> 8) & 0xFF);
|
||||
idx += pDstStep;
|
||||
if (idx < pDst.length) {
|
||||
pDst[idx] = (byte)(lo & 0xFF);
|
||||
if (idx < dst.length) {
|
||||
dst[idx] = (byte)((lo >> 24) & 0xFF);
|
||||
idx += dstStep;
|
||||
if (idx < dst.length) {
|
||||
dst[idx] = (byte)((lo >> 16) & 0xFF);
|
||||
idx += dstStep;
|
||||
if (idx < dst.length) {
|
||||
dst[idx] = (byte)((lo >> 8) & 0xFF);
|
||||
idx += dstStep;
|
||||
if (idx < dst.length) {
|
||||
dst[idx] = (byte)(lo & 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -137,16 +137,16 @@ final class IFFUtil {
|
||||
* Rotate bits counterclockwise.
|
||||
* The IFFImageWriter uses this to convert pixel bits from chunky to planar.
|
||||
*
|
||||
* @param pSrc source pixel data (only lower 8 bits used)
|
||||
* @param pSrcPos starting index of 8 x 8 bit source tile
|
||||
* @param pSrcStep byte offset between adjacent rows in source
|
||||
* @param pDst destination pixel data
|
||||
* @param pDstPos starting index of 8 x 8 bit destination tile
|
||||
* @param pDstStep byte offset between adjacent rows in destination
|
||||
* @param src source pixel data (only lower 8 bits used)
|
||||
* @param srcPos starting index of 8 x 8 bit source tile
|
||||
* @param srcStep byte offset between adjacent rows in source
|
||||
* @param dst destination pixel data
|
||||
* @param dstPos starting index of 8 x 8 bit destination tile
|
||||
* @param dstStep byte offset between adjacent rows in destination
|
||||
*/
|
||||
static void bitRotateCCW(final int[] pSrc, int pSrcPos, int pSrcStep,
|
||||
final byte[] pDst, int pDstPos, int pDstStep) {
|
||||
int idx = pSrcPos;
|
||||
static void bitRotateCCW(final int[] src, int srcPos, @SuppressWarnings("SameParameterValue") int srcStep,
|
||||
final byte[] dst, int dstPos, int dstStep) {
|
||||
int idx = srcPos;
|
||||
|
||||
int lonyb;
|
||||
int hinyb;
|
||||
@@ -154,48 +154,49 @@ final class IFFUtil {
|
||||
long hi = 0;
|
||||
|
||||
for (int i = 7; i >= 0; i--) {
|
||||
lonyb = pSrc[idx] & 0xF;
|
||||
hinyb = (pSrc[idx] >> 4) & 0xF;
|
||||
lonyb = src[idx] & 0xF;
|
||||
hinyb = (src[idx] >> 4) & 0xF;
|
||||
lo |= RTABLE[i][lonyb];
|
||||
hi |= RTABLE[i][hinyb];
|
||||
idx += pSrcStep;
|
||||
idx += srcStep;
|
||||
}
|
||||
|
||||
idx = pDstPos;
|
||||
idx = dstPos;
|
||||
|
||||
pDst[idx] = (byte)(lo & 0xFF);
|
||||
idx += pDstStep;
|
||||
pDst[idx] = (byte)((lo >> 8) & 0xFF);
|
||||
idx += pDstStep;
|
||||
pDst[idx] = (byte)((lo >> 16) & 0xFF);
|
||||
idx += pDstStep;
|
||||
pDst[idx] = (byte)((lo >> 24) & 0xFF);
|
||||
dst[idx] = (byte)(lo & 0xFF);
|
||||
idx += dstStep;
|
||||
dst[idx] = (byte)((lo >> 8) & 0xFF);
|
||||
idx += dstStep;
|
||||
dst[idx] = (byte)((lo >> 16) & 0xFF);
|
||||
idx += dstStep;
|
||||
dst[idx] = (byte)((lo >> 24) & 0xFF);
|
||||
|
||||
idx += pDstStep;
|
||||
idx += dstStep;
|
||||
|
||||
pDst[idx] = (byte)(hi & 0xFF);
|
||||
idx += pDstStep;
|
||||
pDst[idx] = (byte)((hi >> 8) & 0xFF);
|
||||
idx += pDstStep;
|
||||
pDst[idx] = (byte)((hi >> 16) & 0xFF);
|
||||
idx += pDstStep;
|
||||
pDst[idx] = (byte)((hi >> 24) & 0xFF);
|
||||
dst[idx] = (byte)(hi & 0xFF);
|
||||
idx += dstStep;
|
||||
dst[idx] = (byte)((hi >> 8) & 0xFF);
|
||||
idx += dstStep;
|
||||
dst[idx] = (byte)((hi >> 16) & 0xFF);
|
||||
idx += dstStep;
|
||||
dst[idx] = (byte)((hi >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate bits counterclockwise.
|
||||
* The IFFImageWriter uses this to convert pixel bits from chunky to planar.
|
||||
*
|
||||
* @param pSrc source pixel data
|
||||
* @param pSrcPos starting index of 8 x 8 bit source tile
|
||||
* @param pSrcStep byte offset between adjacent rows in source
|
||||
* @param pDst destination pixel data
|
||||
* @param pDstPos starting index of 8 x 8 bit destination tile
|
||||
* @param pDstStep byte offset between adjacent rows in destination
|
||||
* @param src source pixel data
|
||||
* @param srcPos starting index of 8 x 8 bit source tile
|
||||
* @param srcStep byte offset between adjacent rows in source
|
||||
* @param dst destination pixel data
|
||||
* @param dstPos starting index of 8 x 8 bit destination tile
|
||||
* @param dstStep byte offset between adjacent rows in destination
|
||||
*/
|
||||
static void bitRotateCCW(final byte[] pSrc, int pSrcPos, int pSrcStep,
|
||||
final byte[] pDst, int pDstPos, int pDstStep) {
|
||||
int idx = pSrcPos;
|
||||
@SuppressWarnings("unused")
|
||||
static void bitRotateCCW(final byte[] src, int srcPos, int srcStep,
|
||||
final byte[] dst, int dstPos, int dstStep) {
|
||||
int idx = srcPos;
|
||||
|
||||
int lonyb;
|
||||
int hinyb;
|
||||
@@ -203,57 +204,57 @@ final class IFFUtil {
|
||||
long hi = 0;
|
||||
|
||||
for (int i = 7; i >= 0; i--) {
|
||||
lonyb = pSrc[idx] & 0xF;
|
||||
hinyb = (pSrc[idx] >> 4) & 0xF;
|
||||
lonyb = src[idx] & 0xF;
|
||||
hinyb = (src[idx] >> 4) & 0xF;
|
||||
lo |= RTABLE[i][lonyb];
|
||||
hi |= IFFUtil.RTABLE[i][hinyb];
|
||||
idx += pSrcStep;
|
||||
idx += srcStep;
|
||||
}
|
||||
|
||||
idx = pDstPos;
|
||||
idx = dstPos;
|
||||
|
||||
pDst[idx] = (byte)(lo & 0xFF);
|
||||
idx += pDstStep;
|
||||
pDst[idx] = (byte)((lo >> 8) & 0xFF);
|
||||
idx += pDstStep;
|
||||
pDst[idx] = (byte)((lo >> 16) & 0xFF);
|
||||
idx += pDstStep;
|
||||
pDst[idx] = (byte)((lo >> 24) & 0xFF);
|
||||
dst[idx] = (byte)(lo & 0xFF);
|
||||
idx += dstStep;
|
||||
dst[idx] = (byte)((lo >> 8) & 0xFF);
|
||||
idx += dstStep;
|
||||
dst[idx] = (byte)((lo >> 16) & 0xFF);
|
||||
idx += dstStep;
|
||||
dst[idx] = (byte)((lo >> 24) & 0xFF);
|
||||
|
||||
idx += pDstStep;
|
||||
idx += dstStep;
|
||||
|
||||
pDst[idx] = (byte)(hi & 0xFF);
|
||||
idx += pDstStep;
|
||||
pDst[idx] = (byte)((hi >> 8) & 0xFF);
|
||||
idx += pDstStep;
|
||||
pDst[idx] = (byte)((hi >> 16) & 0xFF);
|
||||
idx += pDstStep;
|
||||
pDst[idx] = (byte)((hi >> 24) & 0xFF);
|
||||
dst[idx] = (byte)(hi & 0xFF);
|
||||
idx += dstStep;
|
||||
dst[idx] = (byte)((hi >> 8) & 0xFF);
|
||||
idx += dstStep;
|
||||
dst[idx] = (byte)((hi >> 16) & 0xFF);
|
||||
idx += dstStep;
|
||||
dst[idx] = (byte)((hi >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a byte array to an int.
|
||||
*
|
||||
* @param pBytes a byte array of length 4
|
||||
* @param bytes a byte array of length 4
|
||||
* @return the bytes converted to an int
|
||||
*
|
||||
* @throws ArrayIndexOutOfBoundsException if length is < 4
|
||||
*/
|
||||
static int toInt(final byte[] pBytes) {
|
||||
return (pBytes[0] & 0xff) << 24 | (pBytes[1] & 0xff) << 16
|
||||
| (pBytes[2] & 0xff) << 8 | (pBytes[3] & 0xff);
|
||||
static int toInt(final byte[] bytes) {
|
||||
return (bytes[0] & 0xff) << 24 | (bytes[1] & 0xff) << 16
|
||||
| (bytes[2] & 0xff) << 8 | (bytes[3] & 0xff);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an int to a four letter String.
|
||||
*
|
||||
* @param pChunkId the chunk identifier
|
||||
* @param chunkId the chunk identifier
|
||||
* @return a String
|
||||
*/
|
||||
static String toChunkStr(int pChunkId) {
|
||||
return new String(new byte[] {(byte) ((pChunkId & 0xff000000) >> 24),
|
||||
(byte) ((pChunkId & 0x00ff0000) >> 16),
|
||||
(byte) ((pChunkId & 0x0000ff00) >> 8),
|
||||
(byte) ((pChunkId & 0x000000ff))});
|
||||
static String toChunkStr(int chunkId) {
|
||||
return new String(new byte[] {(byte) ((chunkId & 0xff000000) >> 24),
|
||||
(byte) ((chunkId & 0x00ff0000) >> 16),
|
||||
(byte) ((chunkId & 0x0000ff00) >> 8),
|
||||
(byte) ((chunkId & 0x000000ff))});
|
||||
}
|
||||
}
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import javax.imageio.ImageWriteParam;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* IFFWriteParam.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: IFFWriteParam.java,v 1.0 03/02/2022 haraldk Exp$
|
||||
*/
|
||||
public final class IFFWriteParam extends ImageWriteParam {
|
||||
|
||||
static final String[] COMPRESSION_TYPES = {"NONE", "RLE"};
|
||||
|
||||
public IFFWriteParam(final Locale locale) {
|
||||
super(locale);
|
||||
|
||||
compressionTypes = COMPRESSION_TYPES;
|
||||
compressionType = compressionTypes[1];
|
||||
|
||||
canWriteCompressed = true;
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -80,9 +80,9 @@ final class MutableIndexColorModel extends ColorModel {
|
||||
// TODO: Move validation to chunk (when reading)
|
||||
if (index >= rgbs.length) {
|
||||
// TODO: Issue IIO warning
|
||||
System.err.printf("warning - palette change register out of range\n");
|
||||
System.err.println("warning - palette change register out of range");
|
||||
System.err.printf(" change structure %d index=%d (max %d)\n", i, index, getMapSize() - 1);
|
||||
System.err.printf(" ignoring it... colors might get messed up from here\n");
|
||||
System.err.println(" ignoring it... colors might get messed up from here");
|
||||
}
|
||||
else if (index != MP_REG_IGNORE) {
|
||||
updateRGB(index, ((changes[i].r & 0xff) << 16) | ((changes[i].g & 0xff) << 8) | (changes[i].b & 0xff));
|
||||
|
||||
+18
-17
@@ -72,42 +72,43 @@ final class PCHGChunk extends AbstractMultiPaletteChunk {
|
||||
private int totalChanges;
|
||||
private int minReg;
|
||||
|
||||
public PCHGChunk(int pChunkLength) {
|
||||
super(IFF.CHUNK_PCHG, pChunkLength);
|
||||
PCHGChunk(int chunkLength) {
|
||||
super(IFF.CHUNK_PCHG, chunkLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
void readChunk(final DataInput pInput) throws IOException {
|
||||
int compression = pInput.readUnsignedShort();
|
||||
int flags = pInput.readUnsignedShort();
|
||||
startLine = pInput.readShort();
|
||||
lineCount = pInput.readUnsignedShort();
|
||||
changedLines = pInput.readUnsignedShort();
|
||||
minReg = pInput.readUnsignedShort();
|
||||
int maxReg = pInput.readUnsignedShort();
|
||||
/*int maxChangesPerLine = */pInput.readUnsignedShort(); // We don't really care, as we're not limited by the Amiga display hardware
|
||||
totalChanges = pInput.readInt();
|
||||
void readChunk(final DataInput input) throws IOException {
|
||||
int compression = input.readUnsignedShort();
|
||||
int flags = input.readUnsignedShort();
|
||||
startLine = input.readShort();
|
||||
lineCount = input.readUnsignedShort();
|
||||
changedLines = input.readUnsignedShort();
|
||||
minReg = input.readUnsignedShort();
|
||||
int maxReg = input.readUnsignedShort();
|
||||
/*int maxChangesPerLine = */
|
||||
input.readUnsignedShort(); // We don't really care, as we're not limited by the Amiga display hardware
|
||||
totalChanges = input.readInt();
|
||||
|
||||
byte[] data;
|
||||
|
||||
switch (compression) {
|
||||
case PCHG_COMP_NONE:
|
||||
data = new byte[chunkLength - 20];
|
||||
pInput.readFully(data);
|
||||
input.readFully(data);
|
||||
|
||||
break;
|
||||
case PCHG_COMP_HUFFMAN:
|
||||
// NOTE: Huffman decompression is completely untested, due to lack of source data (read: Probably broken).
|
||||
int compInfoSize = pInput.readInt();
|
||||
int originalDataSize = pInput.readInt();
|
||||
int compInfoSize = input.readInt();
|
||||
int originalDataSize = input.readInt();
|
||||
|
||||
short[] compTree = new short[compInfoSize / 2];
|
||||
for (int i = 0; i < compTree.length; i++) {
|
||||
compTree[i] = pInput.readShort();
|
||||
compTree[i] = input.readShort();
|
||||
}
|
||||
|
||||
byte[] compData = new byte[chunkLength - 20 - 8 - compInfoSize];
|
||||
pInput.readFully(compData);
|
||||
input.readFully(compData);
|
||||
|
||||
data = new byte[originalDataSize];
|
||||
|
||||
|
||||
Executable → Regular
+87
-94
@@ -1,94 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.servlet.fileupload;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.apache.commons.fileupload.FileItem;
|
||||
import org.apache.commons.fileupload.FileUploadException;
|
||||
|
||||
/**
|
||||
* An {@code UploadedFile} implementation, based on
|
||||
* <a href="http://jakarta.apache.org/commons/fileupload/">Jakarta Commons FileUpload</a>.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: UploadedFileImpl.java#1 $
|
||||
*/
|
||||
@Deprecated
|
||||
class UploadedFileImpl implements UploadedFile {
|
||||
private final FileItem item;
|
||||
|
||||
public UploadedFileImpl(FileItem pItem) {
|
||||
if (pItem == null) {
|
||||
throw new IllegalArgumentException("fileitem == null");
|
||||
}
|
||||
|
||||
item = pItem;
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
return item.getContentType();
|
||||
}
|
||||
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return item.getInputStream();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return item.getName();
|
||||
}
|
||||
|
||||
public long length() {
|
||||
return item.getSize();
|
||||
}
|
||||
|
||||
public void writeTo(File pFile) throws IOException {
|
||||
try {
|
||||
item.write(pFile);
|
||||
}
|
||||
catch(RuntimeException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (FileUploadException e) {
|
||||
// We deliberately change this exception to an IOException, as it really is
|
||||
throw (IOException) new IOException(e.getMessage()).initCause(e);
|
||||
}
|
||||
catch (Exception e) {
|
||||
// Should not really happen, ever
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright (c) 2022, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import com.twelvemonkeys.io.enc.DecodeException;
|
||||
import com.twelvemonkeys.io.enc.Decoder;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* Decoder implementation for Impulse FORM RGB8 RLE compression (type 4).
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: RGB8RLEDecoder.java,v 1.0 28/01/2022 haraldk Exp$
|
||||
*
|
||||
* @see <a href="https://wiki.amigaos.net/wiki/RGBN_and_RGB8_IFF_Image_Data">RGBN and RGB8 IFF Image Data</a>
|
||||
*/
|
||||
final class RGB8RLEDecoder implements Decoder {
|
||||
public int decode(final InputStream stream, final ByteBuffer buffer) throws IOException {
|
||||
while (buffer.remaining() >= 127 * 4) {
|
||||
int r = stream.read();
|
||||
int g = stream.read();
|
||||
int b = stream.read();
|
||||
int a = stream.read();
|
||||
|
||||
if (a < 0) {
|
||||
// Normal EOF
|
||||
if (r == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Partial pixel read...
|
||||
throw new EOFException();
|
||||
}
|
||||
|
||||
// Get "genlock" (transparency) bit + count
|
||||
boolean alpha = (a & 0x80) != 0;
|
||||
int count = a & 0x7f;
|
||||
a = alpha ? 0 : (byte) 0xff; // convert to full transparent/opaque;
|
||||
|
||||
if (count == 0) {
|
||||
throw new DecodeException("Multi-byte counts not supported");
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
buffer.put((byte) r);
|
||||
buffer.put((byte) g);
|
||||
buffer.put((byte) b);
|
||||
buffer.put((byte) a);
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.position();
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -38,8 +38,8 @@ package com.twelvemonkeys.imageio.plugins.iff;
|
||||
* @version $Id: SHAMChunk.java,v 1.0 30.03.12 14:53 haraldk Exp$
|
||||
*/
|
||||
final class SHAMChunk extends AbstractMultiPaletteChunk {
|
||||
protected SHAMChunk(int pChunkLength) {
|
||||
super(IFF.CHUNK_SHAM, pChunkLength);
|
||||
SHAMChunk(int chunkLength) {
|
||||
super(IFF.CHUNK_SHAM, chunkLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* XS24Chunk.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: XS24Chunk.java,v 1.0 01/02/2022 haraldk Exp$
|
||||
*/
|
||||
final class XS24Chunk extends IFFChunk {
|
||||
private byte[] data;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
XS24Chunk(final int chunkLength) {
|
||||
super(IFF.CHUNK_XS24, chunkLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
void readChunk(final DataInput input) throws IOException {
|
||||
width = input.readUnsignedShort();
|
||||
height = input.readUnsignedShort();
|
||||
input.readShort(); // Not sure what this is?
|
||||
|
||||
int dataLength = width * height * 3;
|
||||
if (dataLength > chunkLength - 6) {
|
||||
throw new IIOException("Bad XS24 chunk: " + width + " * " + height + " * 3 > chunk length (" + chunkLength + ")");
|
||||
}
|
||||
|
||||
data = new byte[dataLength];
|
||||
|
||||
input.readFully(data);
|
||||
|
||||
// Skip pad
|
||||
for (int i = 0; i < chunkLength - dataLength - 6; i++) {
|
||||
input.readByte();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void writeChunk(final DataOutput output) {
|
||||
throw new InternalError("Not implemented: writeChunk()");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString()
|
||||
+ "{thumbnail=" + data.length + '}';
|
||||
}
|
||||
|
||||
public BufferedImage thumbnail() {
|
||||
BufferedImage thumbnail = ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR)
|
||||
.createBufferedImage(width, height);
|
||||
thumbnail.getRaster().setDataElements(0, 0, width, height, data);
|
||||
return thumbnail;
|
||||
}
|
||||
}
|
||||
+263
-91
@@ -1,26 +1,24 @@
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.awt.image.IndexColorModel;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
||||
import javax.imageio.metadata.IIOMetadataNode;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.function.ThrowingRunnable;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
||||
import javax.imageio.metadata.IIOMetadataNode;
|
||||
import java.awt.image.IndexColorModel;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class IFFImageMetadataTest {
|
||||
@Test
|
||||
public void testStandardFeatures() {
|
||||
BMHDChunk header = new BMHDChunk(300, 200, 24, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
||||
public void testStandardFeatures() throws IIOException {
|
||||
Form header = Form.ofType(IFF.TYPE_ILBM)
|
||||
.with(new BMHDChunk(300, 200, 24, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0));
|
||||
|
||||
final IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, Collections.<GenericChunk>emptyList());
|
||||
final IFFImageMetadata metadata = new IFFImageMetadata(header, null);
|
||||
|
||||
// Standard metadata format
|
||||
assertTrue(metadata.isStandardMetadataFormatSupported());
|
||||
@@ -49,10 +47,11 @@ public class IFFImageMetadataTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStandardChromaGray() {
|
||||
BMHDChunk header = new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
||||
public void testStandardChromaGray() throws IIOException {
|
||||
Form header = Form.ofType(IFF.TYPE_ILBM)
|
||||
.with(new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0));
|
||||
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, Collections.<GenericChunk>emptyList());
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(header, null);
|
||||
|
||||
IIOMetadataNode chroma = metadata.getStandardChromaNode();
|
||||
assertNotNull(chroma);
|
||||
@@ -75,10 +74,11 @@ public class IFFImageMetadataTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStandardChromaRGB() {
|
||||
BMHDChunk header = new BMHDChunk(300, 200, 24, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
||||
public void testStandardChromaRGB() throws IIOException {
|
||||
Form header = Form.ofType(IFF.TYPE_ILBM)
|
||||
.with(new BMHDChunk(300, 200, 24, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0));
|
||||
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, Collections.<GenericChunk>emptyList());
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(header, null);
|
||||
|
||||
IIOMetadataNode chroma = metadata.getStandardChromaNode();
|
||||
assertNotNull(chroma);
|
||||
@@ -101,16 +101,17 @@ public class IFFImageMetadataTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStandardChromaPalette() {
|
||||
BMHDChunk header = new BMHDChunk(300, 200, 1, BMHDChunk.MASK_TRANSPARENT_COLOR, BMHDChunk.COMPRESSION_BYTE_RUN, 1);
|
||||
public void testStandardChromaPalette() throws IIOException {
|
||||
Form header = Form.ofType(IFF.TYPE_ILBM)
|
||||
.with(new BMHDChunk(300, 200, 1, BMHDChunk.MASK_TRANSPARENT_COLOR, BMHDChunk.COMPRESSION_BYTE_RUN, 1));
|
||||
|
||||
byte[] bw = {0, (byte) 0xff};
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, new IndexColorModel(header.bitplanes, bw.length, bw, bw, bw, header.transparentIndex), null, Collections.<GenericChunk>emptyList());
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(header, new IndexColorModel(header.bitplanes(), bw.length, bw, bw, bw, header.transparentIndex()));
|
||||
|
||||
IIOMetadataNode chroma = metadata.getStandardChromaNode();
|
||||
assertNotNull(chroma);
|
||||
assertEquals("Chroma", chroma.getNodeName());
|
||||
assertEquals(4, chroma.getLength());
|
||||
assertEquals(5, chroma.getLength());
|
||||
|
||||
IIOMetadataNode colorSpaceType = (IIOMetadataNode) chroma.getFirstChild();
|
||||
assertEquals("ColorSpaceType", colorSpaceType.getNodeName());
|
||||
@@ -138,14 +139,21 @@ public class IFFImageMetadataTest {
|
||||
assertEquals(rgb, item0.getAttribute("blue"));
|
||||
}
|
||||
|
||||
// TODO: BackgroundIndex == 1??
|
||||
// BackgroundIndex == 1
|
||||
IIOMetadataNode backgroundIndex = (IIOMetadataNode) palette.getNextSibling();
|
||||
assertEquals("BackgroundIndex", backgroundIndex.getNodeName());
|
||||
assertEquals("1", backgroundIndex.getAttribute("value"));
|
||||
|
||||
// No more elements
|
||||
assertNull(backgroundIndex.getNextSibling());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStandardCompressionRLE() {
|
||||
BMHDChunk header = new BMHDChunk(300, 200, 24, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
||||
public void testStandardCompressionRLE() throws IIOException {
|
||||
Form header = Form.ofType(IFF.TYPE_ILBM)
|
||||
.with(new BMHDChunk(300, 200, 24, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0));
|
||||
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, Collections.<GenericChunk>emptyList());
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(header, null);
|
||||
|
||||
IIOMetadataNode compression = metadata.getStandardCompressionNode();
|
||||
assertNotNull(compression);
|
||||
@@ -164,19 +172,21 @@ public class IFFImageMetadataTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStandardCompressionNone() {
|
||||
BMHDChunk header = new BMHDChunk(300, 200, 24, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_NONE, 0);
|
||||
public void testStandardCompressionNone() throws IIOException {
|
||||
Form header = Form.ofType(IFF.TYPE_ILBM)
|
||||
.with(new BMHDChunk(300, 200, 24, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_NONE, 0));
|
||||
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, Collections.<GenericChunk>emptyList());
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(header, null);
|
||||
|
||||
assertNull(metadata.getStandardCompressionNode()); // No compression, all default...
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStandardDataILBM_Gray() {
|
||||
BMHDChunk header = new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
||||
public void testStandardDataILBM_Gray() throws IIOException {
|
||||
Form header = Form.ofType(IFF.TYPE_ILBM)
|
||||
.with(new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0));
|
||||
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, Collections.<GenericChunk>emptyList());
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(header, null);
|
||||
|
||||
IIOMetadataNode data = metadata.getStandardDataNode();
|
||||
assertNotNull(data);
|
||||
@@ -199,10 +209,11 @@ public class IFFImageMetadataTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStandardDataILBM_RGB() {
|
||||
BMHDChunk header = new BMHDChunk(300, 200, 24, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
||||
public void testStandardDataILBM_RGB() throws IIOException {
|
||||
Form header = Form.ofType(IFF.TYPE_ILBM)
|
||||
.with(new BMHDChunk(300, 200, 24, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0));
|
||||
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, Collections.<GenericChunk>emptyList());
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(header, null);
|
||||
|
||||
IIOMetadataNode data = metadata.getStandardDataNode();
|
||||
assertNotNull(data);
|
||||
@@ -225,10 +236,11 @@ public class IFFImageMetadataTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStandardDataILBM_RGBA() {
|
||||
BMHDChunk header = new BMHDChunk(300, 200, 32, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
||||
public void testStandardDataILBM_RGBA() throws IIOException {
|
||||
Form header = Form.ofType(IFF.TYPE_ILBM)
|
||||
.with(new BMHDChunk(300, 200, 32, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0));
|
||||
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, Collections.<GenericChunk>emptyList());
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(header, null);
|
||||
|
||||
IIOMetadataNode data = metadata.getStandardDataNode();
|
||||
assertNotNull(data);
|
||||
@@ -251,12 +263,13 @@ public class IFFImageMetadataTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStandardDataILBM_Palette() {
|
||||
public void testStandardDataILBM_Palette() throws IIOException {
|
||||
for (int i = 1; i <= 8; i++) {
|
||||
BMHDChunk header = new BMHDChunk(300, 200, i, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
||||
Form header = Form.ofType(IFF.TYPE_ILBM)
|
||||
.with(new BMHDChunk(300, 200, i, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0));
|
||||
|
||||
byte[] rgb = new byte[2 << i]; // Colors doesn't really matter here
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, new IndexColorModel(header.bitplanes, rgb.length, rgb, rgb, rgb, 0), null, Collections.<GenericChunk>emptyList());
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(header, new IndexColorModel(header.bitplanes(), rgb.length, rgb, rgb, rgb, 0));
|
||||
|
||||
IIOMetadataNode data = metadata.getStandardDataNode();
|
||||
assertNotNull(data);
|
||||
@@ -280,10 +293,11 @@ public class IFFImageMetadataTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStandardDataPBM_Gray() {
|
||||
BMHDChunk header = new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
||||
public void testStandardDataPBM_Gray() throws IIOException {
|
||||
Form header = Form.ofType(IFF.TYPE_PBM)
|
||||
.with(new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0));
|
||||
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_PBM, header, null, null, Collections.<GenericChunk>emptyList());
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(header, null);
|
||||
|
||||
IIOMetadataNode data = metadata.getStandardDataNode();
|
||||
assertNotNull(data);
|
||||
@@ -306,10 +320,11 @@ public class IFFImageMetadataTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStandardDataPBM_RGB() {
|
||||
BMHDChunk header = new BMHDChunk(300, 200, 24, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
||||
public void testStandardDataPBM_RGB() throws IIOException {
|
||||
Form header = Form.ofType(IFF.TYPE_PBM)
|
||||
.with(new BMHDChunk(300, 200, 24, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0));
|
||||
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_PBM, header, null, null, Collections.<GenericChunk>emptyList());
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(header, null);
|
||||
|
||||
IIOMetadataNode data = metadata.getStandardDataNode();
|
||||
assertNotNull(data);
|
||||
@@ -333,40 +348,57 @@ public class IFFImageMetadataTest {
|
||||
|
||||
|
||||
@Test
|
||||
public void testStandardDimensionNoViewport() {
|
||||
BMHDChunk header = new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
||||
public void testStandardDimensionNoViewport() throws IIOException {
|
||||
BMHDChunk bitmapHeader = new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
||||
bitmapHeader.xAspect = 0;
|
||||
bitmapHeader.yAspect = 0;
|
||||
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, Collections.<GenericChunk>emptyList());
|
||||
Form header = Form.ofType(IFF.TYPE_ILBM)
|
||||
.with(bitmapHeader);
|
||||
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(header, null);
|
||||
|
||||
IIOMetadataNode dimension = metadata.getStandardDimensionNode();
|
||||
assertNull(dimension);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStandardDimensionNormal() {
|
||||
BMHDChunk header = new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
||||
public void testStandardDimensionNormal() throws IIOException {
|
||||
Form header = Form.ofType(IFF.TYPE_ILBM)
|
||||
.with(new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0))
|
||||
.with(new CAMGChunk(4));
|
||||
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, new CAMGChunk(4), Collections.<GenericChunk>emptyList());
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(header, null);
|
||||
|
||||
IIOMetadataNode dimension = metadata.getStandardDimensionNode();
|
||||
assertNotNull(dimension);
|
||||
assertEquals("Dimension", dimension.getNodeName());
|
||||
assertEquals(1, dimension.getLength());
|
||||
|
||||
IIOMetadataNode pixelAspectRatio = (IIOMetadataNode) dimension.getFirstChild();
|
||||
assertEquals("PixelAspectRatio", pixelAspectRatio.getNodeName());
|
||||
assertEquals("1.0", pixelAspectRatio.getAttribute("value"));
|
||||
// No Dimension node is okay, or one with an aspect ratio of 1.0
|
||||
if (dimension != null) {
|
||||
assertEquals("Dimension", dimension.getNodeName());
|
||||
assertEquals(1, dimension.getLength());
|
||||
|
||||
assertNull(pixelAspectRatio.getNextSibling()); // No more children
|
||||
IIOMetadataNode pixelAspectRatio = (IIOMetadataNode) dimension.getFirstChild();
|
||||
assertEquals("PixelAspectRatio", pixelAspectRatio.getNodeName());
|
||||
assertEquals("1.0", pixelAspectRatio.getAttribute("value"));
|
||||
|
||||
assertNull(pixelAspectRatio.getNextSibling()); // No more children
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStandardDimensionHires() {
|
||||
BMHDChunk header = new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
||||
public void testStandardDimensionHires() throws IIOException {
|
||||
BMHDChunk bitmapHeader = new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
||||
bitmapHeader.xAspect = 2;
|
||||
bitmapHeader.yAspect = 1;
|
||||
|
||||
CAMGChunk viewPort = new CAMGChunk(4);
|
||||
viewPort.camg = 0x8000;
|
||||
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, viewPort, Collections.<GenericChunk>emptyList());
|
||||
Form header = Form.ofType(IFF.TYPE_ILBM)
|
||||
.with(bitmapHeader)
|
||||
.with(viewPort);
|
||||
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(header, null);
|
||||
|
||||
IIOMetadataNode dimension = metadata.getStandardDimensionNode();
|
||||
assertNotNull(dimension);
|
||||
@@ -381,13 +413,19 @@ public class IFFImageMetadataTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStandardDimensionInterlaced() {
|
||||
BMHDChunk header = new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
||||
public void testStandardDimensionInterlaced() throws IIOException {
|
||||
BMHDChunk bitmapHeader = new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
||||
bitmapHeader.xAspect = 1;
|
||||
bitmapHeader.yAspect = 2;
|
||||
|
||||
CAMGChunk viewPort = new CAMGChunk(4);
|
||||
viewPort.camg = 0x4;
|
||||
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, viewPort, Collections.<GenericChunk>emptyList());
|
||||
Form header = Form.ofType(IFF.TYPE_ILBM)
|
||||
.with(bitmapHeader)
|
||||
.with(viewPort);
|
||||
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(header, null);
|
||||
|
||||
IIOMetadataNode dimension = metadata.getStandardDimensionNode();
|
||||
assertNotNull(dimension);
|
||||
@@ -402,13 +440,14 @@ public class IFFImageMetadataTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStandardDimensionHiresInterlaced() {
|
||||
BMHDChunk header = new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
||||
|
||||
public void testStandardDimensionHiresInterlaced() throws IIOException {
|
||||
CAMGChunk viewPort = new CAMGChunk(4);
|
||||
viewPort.camg = 0x8004;
|
||||
Form header = Form.ofType(IFF.TYPE_ILBM)
|
||||
.with(new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0))
|
||||
.with(viewPort);
|
||||
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, viewPort, Collections.<GenericChunk>emptyList());
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(header, null);
|
||||
|
||||
IIOMetadataNode dimension = metadata.getStandardDimensionNode();
|
||||
assertNotNull(dimension);
|
||||
@@ -423,10 +462,11 @@ public class IFFImageMetadataTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStandardDocument() {
|
||||
BMHDChunk header = new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
||||
public void testStandardDocument() throws IIOException {
|
||||
Form header = Form.ofType(IFF.TYPE_ILBM)
|
||||
.with(new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0));
|
||||
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, Collections.<GenericChunk>emptyList());
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(header, null);
|
||||
|
||||
IIOMetadataNode document = metadata.getStandardDocumentNode();
|
||||
assertNotNull(document);
|
||||
@@ -441,13 +481,15 @@ public class IFFImageMetadataTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStandardText() {
|
||||
BMHDChunk header = new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
||||
|
||||
public void testStandardText() throws IIOException {
|
||||
int[] chunks = {IFF.CHUNK_ANNO, IFF.CHUNK_UTF8};
|
||||
String[] texts = {"annotation", "äñnótâtïøñ"};
|
||||
List<GenericChunk> meta = Arrays.asList(new GenericChunk(IFF.CHUNK_ANNO, texts[0].getBytes(StandardCharsets.US_ASCII)),
|
||||
new GenericChunk(IFF.CHUNK_UTF8, texts[1].getBytes(StandardCharsets.UTF_8)));
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, meta);
|
||||
Form header = Form.ofType(IFF.TYPE_ILBM)
|
||||
.with(new BMHDChunk(300, 200, 8, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0))
|
||||
.with(new GenericChunk(chunks[0], texts[0].getBytes(StandardCharsets.US_ASCII)))
|
||||
.with(new GenericChunk(chunks[1], texts[1].getBytes(StandardCharsets.UTF_8)));
|
||||
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(header, null);
|
||||
|
||||
IIOMetadataNode text = metadata.getStandardTextNode();
|
||||
assertNotNull(text);
|
||||
@@ -457,26 +499,28 @@ public class IFFImageMetadataTest {
|
||||
for (int i = 0; i < texts.length; i++) {
|
||||
IIOMetadataNode textEntry = (IIOMetadataNode) text.item(i);
|
||||
assertEquals("TextEntry", textEntry.getNodeName());
|
||||
assertEquals(IFFUtil.toChunkStr(meta.get(i).chunkId), textEntry.getAttribute("keyword"));
|
||||
assertEquals(IFFUtil.toChunkStr(chunks[i]), textEntry.getAttribute("keyword"));
|
||||
assertEquals(texts[i], textEntry.getAttribute("value"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStandardTransparencyRGB() {
|
||||
BMHDChunk header = new BMHDChunk(300, 200, 24, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
||||
public void testStandardTransparencyRGB() throws IIOException {
|
||||
Form header = Form.ofType(IFF.TYPE_ILBM)
|
||||
.with(new BMHDChunk(300, 200, 24, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0));
|
||||
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, Collections.<GenericChunk>emptyList());
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(header, null);
|
||||
|
||||
IIOMetadataNode transparency = metadata.getStandardTransparencyNode();
|
||||
assertNull(transparency); // No transparency, just defaults
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStandardTransparencyRGBA() {
|
||||
BMHDChunk header = new BMHDChunk(300, 200, 32, BMHDChunk.MASK_HAS_MASK, BMHDChunk.COMPRESSION_BYTE_RUN, 0);
|
||||
public void testStandardTransparencyRGBA() throws IIOException {
|
||||
Form header = Form.ofType(IFF.TYPE_ILBM)
|
||||
.with(new BMHDChunk(300, 200, 32, BMHDChunk.MASK_HAS_MASK, BMHDChunk.COMPRESSION_BYTE_RUN, 0));
|
||||
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, null, null, Collections.<GenericChunk>emptyList());
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(header, null);
|
||||
|
||||
IIOMetadataNode transparency = metadata.getStandardTransparencyNode();
|
||||
assertNotNull(transparency);
|
||||
@@ -491,11 +535,12 @@ public class IFFImageMetadataTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStandardTransparencyPalette() {
|
||||
BMHDChunk header = new BMHDChunk(300, 200, 1, BMHDChunk.MASK_TRANSPARENT_COLOR, BMHDChunk.COMPRESSION_BYTE_RUN, 1);
|
||||
public void testStandardTransparencyPalette() throws IIOException {
|
||||
Form header = Form.ofType(IFF.TYPE_ILBM)
|
||||
.with(new BMHDChunk(300, 200, 1, BMHDChunk.MASK_TRANSPARENT_COLOR, BMHDChunk.COMPRESSION_BYTE_RUN, 1));
|
||||
|
||||
byte[] bw = {0, (byte) 0xff};
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(IFF.TYPE_ILBM, header, new IndexColorModel(header.bitplanes, bw.length, bw, bw, bw, header.transparentIndex), null, Collections.<GenericChunk>emptyList());
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(header, new IndexColorModel(header.bitplanes(), bw.length, bw, bw, bw, header.transparentIndex()));
|
||||
|
||||
IIOMetadataNode transparency = metadata.getStandardTransparencyNode();
|
||||
assertNotNull(transparency);
|
||||
@@ -508,4 +553,131 @@ public class IFFImageMetadataTest {
|
||||
|
||||
assertNull(pixelAspectRatio.getNextSibling()); // No more children
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStandardRGB8() throws IIOException {
|
||||
Form header = Form.ofType(IFF.TYPE_RGB8)
|
||||
.with(new BMHDChunk(300, 200, 25, BMHDChunk.MASK_NONE, BMHDChunk.COMPRESSION_BYTE_RUN, 0));
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(header, null);
|
||||
|
||||
// Chroma
|
||||
IIOMetadataNode chroma = metadata.getStandardChromaNode();
|
||||
assertNotNull(chroma);
|
||||
assertEquals("Chroma", chroma.getNodeName());
|
||||
assertEquals(3, chroma.getLength());
|
||||
|
||||
IIOMetadataNode colorSpaceType = (IIOMetadataNode) chroma.getFirstChild();
|
||||
assertEquals("ColorSpaceType", colorSpaceType.getNodeName());
|
||||
assertEquals("RGB", colorSpaceType.getAttribute("name"));
|
||||
|
||||
IIOMetadataNode numChannels = (IIOMetadataNode) colorSpaceType.getNextSibling();
|
||||
assertEquals("NumChannels", numChannels.getNodeName());
|
||||
assertEquals("4", numChannels.getAttribute("value"));
|
||||
|
||||
IIOMetadataNode blackIsZero = (IIOMetadataNode) numChannels.getNextSibling();
|
||||
assertEquals("BlackIsZero", blackIsZero.getNodeName());
|
||||
assertEquals("TRUE", blackIsZero.getAttribute("value"));
|
||||
|
||||
assertNull(blackIsZero.getNextSibling()); // No more children
|
||||
|
||||
// Data
|
||||
IIOMetadataNode data = metadata.getStandardDataNode();
|
||||
assertNotNull(data);
|
||||
assertEquals("Data", data.getNodeName());
|
||||
assertEquals(3, data.getLength());
|
||||
|
||||
IIOMetadataNode planarConfiguration = (IIOMetadataNode) data.getFirstChild();
|
||||
assertEquals("PlanarConfiguration", planarConfiguration.getNodeName());
|
||||
assertEquals("PixelInterleaved", planarConfiguration.getAttribute("value"));
|
||||
|
||||
IIOMetadataNode sampleFormat = (IIOMetadataNode) planarConfiguration.getNextSibling();
|
||||
assertEquals("SampleFormat", sampleFormat.getNodeName());
|
||||
assertEquals("UnsignedIntegral", sampleFormat.getAttribute("value"));
|
||||
|
||||
IIOMetadataNode bitsPerSample = (IIOMetadataNode) sampleFormat.getNextSibling();
|
||||
assertEquals("BitsPerSample", bitsPerSample.getNodeName());
|
||||
assertEquals("8 8 8 1", bitsPerSample.getAttribute("value"));
|
||||
|
||||
assertNull(bitsPerSample.getNextSibling()); // No more children
|
||||
|
||||
// Transparency
|
||||
IIOMetadataNode transparency = metadata.getStandardTransparencyNode();
|
||||
assertNotNull(transparency);
|
||||
assertEquals("Transparency", transparency.getNodeName());
|
||||
assertEquals(1, transparency.getLength());
|
||||
|
||||
IIOMetadataNode alpha = (IIOMetadataNode) transparency.getFirstChild();
|
||||
assertEquals("Alpha", alpha.getNodeName());
|
||||
assertEquals("nonpremultiplied", alpha.getAttribute("value"));
|
||||
|
||||
assertNull(alpha.getNextSibling()); // No more children
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStandardDEEP() throws IIOException {
|
||||
DPELChunk dpel = new DPELChunk(20);
|
||||
dpel.typeDepths = new DPELChunk.TypeDepth[4];
|
||||
for (int i = 0; i < dpel.typeDepths.length; i++) {
|
||||
dpel.typeDepths[i] = new DPELChunk.TypeDepth(i == 0 ? 11 : i, 8);
|
||||
}
|
||||
|
||||
Form header = Form.ofType(IFF.TYPE_DEEP)
|
||||
.with(new DGBLChunk(8))
|
||||
.with(dpel);
|
||||
IFFImageMetadata metadata = new IFFImageMetadata(header, null);
|
||||
|
||||
// Chroma
|
||||
IIOMetadataNode chroma = metadata.getStandardChromaNode();
|
||||
assertNotNull(chroma);
|
||||
assertEquals("Chroma", chroma.getNodeName());
|
||||
assertEquals(3, chroma.getLength());
|
||||
|
||||
IIOMetadataNode colorSpaceType = (IIOMetadataNode) chroma.getFirstChild();
|
||||
assertEquals("ColorSpaceType", colorSpaceType.getNodeName());
|
||||
assertEquals("RGB", colorSpaceType.getAttribute("name"));
|
||||
|
||||
IIOMetadataNode numChannels = (IIOMetadataNode) colorSpaceType.getNextSibling();
|
||||
assertEquals("NumChannels", numChannels.getNodeName());
|
||||
assertEquals("4", numChannels.getAttribute("value"));
|
||||
|
||||
IIOMetadataNode blackIsZero = (IIOMetadataNode) numChannels.getNextSibling();
|
||||
assertEquals("BlackIsZero", blackIsZero.getNodeName());
|
||||
assertEquals("TRUE", blackIsZero.getAttribute("value"));
|
||||
|
||||
// TODO: BackgroundColor = 0x666666
|
||||
|
||||
assertNull(blackIsZero.getNextSibling()); // No more children
|
||||
|
||||
// Data
|
||||
IIOMetadataNode data = metadata.getStandardDataNode();
|
||||
assertNotNull(data);
|
||||
assertEquals("Data", data.getNodeName());
|
||||
assertEquals(3, data.getLength());
|
||||
|
||||
IIOMetadataNode planarConfiguration = (IIOMetadataNode) data.getFirstChild();
|
||||
assertEquals("PlanarConfiguration", planarConfiguration.getNodeName());
|
||||
assertEquals("PixelInterleaved", planarConfiguration.getAttribute("value"));
|
||||
|
||||
IIOMetadataNode sampleFormat = (IIOMetadataNode) planarConfiguration.getNextSibling();
|
||||
assertEquals("SampleFormat", sampleFormat.getNodeName());
|
||||
assertEquals("UnsignedIntegral", sampleFormat.getAttribute("value"));
|
||||
|
||||
IIOMetadataNode bitsPerSample = (IIOMetadataNode) sampleFormat.getNextSibling();
|
||||
assertEquals("BitsPerSample", bitsPerSample.getNodeName());
|
||||
assertEquals("8 8 8 8", bitsPerSample.getAttribute("value"));
|
||||
|
||||
assertNull(bitsPerSample.getNextSibling()); // No more children
|
||||
|
||||
// Transparency
|
||||
IIOMetadataNode transparency = metadata.getStandardTransparencyNode();
|
||||
assertNotNull(transparency);
|
||||
assertEquals("Transparency", transparency.getNodeName());
|
||||
assertEquals(1, transparency.getLength());
|
||||
|
||||
IIOMetadataNode alpha = (IIOMetadataNode) transparency.getFirstChild();
|
||||
assertEquals("Alpha", alpha.getNodeName());
|
||||
assertEquals("premultiplied", alpha.getAttribute("value"));
|
||||
|
||||
assertNull(alpha.getNextSibling()); // No more children
|
||||
}
|
||||
}
|
||||
+19
-5
@@ -88,7 +88,16 @@ public class IFFImageReaderTest extends ImageReaderAbstractTest<IFFImageReader>
|
||||
// 16 color indexed, multi palette (PCHG) - Ok
|
||||
new TestData(getClassLoaderResource("/iff/Manhattan.PCHG"), new Dimension(704, 440)),
|
||||
// 16 color indexed, multi palette (PCHG + SHAM) - Ok
|
||||
new TestData(getClassLoaderResource("/iff/Somnambulist-2.SHAM"), new Dimension(704, 440))
|
||||
new TestData(getClassLoaderResource("/iff/Somnambulist-2.SHAM"), new Dimension(704, 440)),
|
||||
// Impulse RGB8 format straight from Imagine 2.0
|
||||
new TestData(getClassLoaderResource("/iff/glowsphere2.rgb8"), new Dimension(640, 480)),
|
||||
// Impulse RGB8 format written by ASDG ADPro, with cross boundary runs, which is probably not as per spec...
|
||||
new TestData(getClassLoaderResource("/iff/tunnel04-adpro-cross-boundary-runs.rgb8"), new Dimension(640, 480)),
|
||||
// TVPaint (TecSoft) DEEP format
|
||||
new TestData(getClassLoaderResource("/iff/arch.deep"), new Dimension(800, 600)),
|
||||
// TVPaint Project (TVPP is effectively same as the DEEP format, but multiple layers, background color etc.)
|
||||
// TODO: This file contains one more image/layer, second DBOD chunk @1868908, len: 1199144!
|
||||
new TestData(getClassLoaderResource("/iff/warm-and-bright.pro"), new Dimension(800, 600))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -99,7 +108,7 @@ public class IFFImageReaderTest extends ImageReaderAbstractTest<IFFImageReader>
|
||||
|
||||
@Override
|
||||
protected List<String> getSuffixes() {
|
||||
return Arrays.asList("iff", "ilbm", "ham", "ham8", "lbm");
|
||||
return Arrays.asList("iff", "ilbm", "ham", "ham8", "lbm", "rgb8", "deep");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -134,9 +143,14 @@ public class IFFImageReaderTest extends ImageReaderAbstractTest<IFFImageReader>
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
// Make sure the color model is really EHB
|
||||
assertEquals("red", (reds[i] & 0xff) / 2, reds[i + 32] & 0xff);
|
||||
assertEquals("blue", (blues[i] & 0xff) / 2, blues[i + 32] & 0xff);
|
||||
assertEquals("green", (greens[i] & 0xff) / 2, greens[i + 32] & 0xff);
|
||||
try {
|
||||
assertEquals("red", (reds[i] & 0xff) / 2, reds[i + 32] & 0xff);
|
||||
assertEquals("blue", (blues[i] & 0xff) / 2, blues[i + 32] & 0xff);
|
||||
assertEquals("green", (greens[i] & 0xff) / 2, greens[i + 32] & 0xff);
|
||||
}
|
||||
catch (AssertionError err) {
|
||||
throw new AssertionError("Color " + i + " " + err.getMessage(), err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
package com.twelvemonkeys.imageio.plugins.iff;
|
||||
|
||||
import com.twelvemonkeys.io.enc.DecodeException;
|
||||
import com.twelvemonkeys.io.enc.Decoder;
|
||||
import com.twelvemonkeys.io.enc.DecoderAbstractTest;
|
||||
import com.twelvemonkeys.io.enc.Encoder;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* RGB8RLEDecoderTest.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: RGB8RLEDecoderTest.java,v 1.0 28/01/2022 haraldk Exp$
|
||||
*/
|
||||
public class RGB8RLEDecoderTest extends DecoderAbstractTest {
|
||||
|
||||
public static final int BUFFER_SIZE = 1024;
|
||||
|
||||
@Override
|
||||
public Decoder createDecoder() {
|
||||
return new RGB8RLEDecoder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Encoder createCompatibleEncoder() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testDecodeEmpty() throws IOException {
|
||||
Decoder decoder = createDecoder();
|
||||
ByteArrayInputStream bytes = new ByteArrayInputStream(new byte[0]);
|
||||
|
||||
int count = decoder.decode(bytes, ByteBuffer.allocate(BUFFER_SIZE));
|
||||
assertEquals("Should not be able to read any bytes", 0, count);
|
||||
}
|
||||
|
||||
@Test(expected = EOFException.class)
|
||||
public final void testDecodePartial() throws IOException {
|
||||
Decoder decoder = createDecoder();
|
||||
ByteArrayInputStream bytes = new ByteArrayInputStream(new byte[] {0});
|
||||
|
||||
decoder.decode(bytes, ByteBuffer.allocate(BUFFER_SIZE));
|
||||
fail("Should not be able to read any bytes");
|
||||
}
|
||||
|
||||
@Test(expected = EOFException.class)
|
||||
public final void testDecodePartialToo() throws IOException {
|
||||
Decoder decoder = createDecoder();
|
||||
ByteArrayInputStream bytes = new ByteArrayInputStream(new byte[] {0, 0, 0, 1, 0, 0});
|
||||
|
||||
decoder.decode(bytes, ByteBuffer.allocate(BUFFER_SIZE));
|
||||
fail("Should not be able to read any bytes");
|
||||
}
|
||||
|
||||
@Test(expected = DecodeException.class)
|
||||
public final void testDecodeZeroRun() throws IOException {
|
||||
// The spec says that 0-runs should be used to signal that the run is > 127,
|
||||
// and contained in the next byte, however, this is not used in practise and not supported.
|
||||
Decoder decoder = createDecoder();
|
||||
ByteArrayInputStream bytes = new ByteArrayInputStream(new byte[] {0, 0, 0, 0});
|
||||
|
||||
decoder.decode(bytes, ByteBuffer.allocate(BUFFER_SIZE));
|
||||
fail("Should not be able to read any bytes");
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testDecodeSingleOpaque() throws IOException {
|
||||
Decoder decoder = createDecoder();
|
||||
ByteArrayInputStream bytes = new ByteArrayInputStream(new byte[] {0, 0, 0, 1});
|
||||
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
|
||||
|
||||
int count = decoder.decode(bytes, buffer);
|
||||
|
||||
assertEquals(4, count);
|
||||
assertEquals(0x000000FF, buffer.getInt(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testDecodeSingleTransparent() throws IOException {
|
||||
Decoder decoder = createDecoder();
|
||||
ByteArrayInputStream bytes = new ByteArrayInputStream(new byte[] {0, 0, 0, (byte) 0x81});
|
||||
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
|
||||
|
||||
int count = decoder.decode(bytes, buffer);
|
||||
|
||||
assertEquals(4, count);
|
||||
assertEquals(0x00000000, buffer.getInt(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testDecodeMaxRun() throws IOException {
|
||||
Decoder decoder = createDecoder();
|
||||
ByteArrayInputStream bytes = new ByteArrayInputStream(new byte[] {(byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x7F});
|
||||
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
|
||||
|
||||
int count = decoder.decode(bytes, buffer);
|
||||
|
||||
assertEquals(127 * 4, count);
|
||||
for (int i = 0; i < 127; i++) {
|
||||
assertEquals(0xFFFFFFFF, buffer.getInt(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<version>3.8.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-jpeg-jai-interop</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: JPEG/JAI TIFF Interop</name>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<version>3.8.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-jpeg-jep262-interop</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: JPEG/JEP-262 Interop</name>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<version>3.8.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-jpeg</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: JPEG plugin</name>
|
||||
|
||||
+28
-11
@@ -35,6 +35,7 @@ import com.twelvemonkeys.imageio.metadata.Directory;
|
||||
import com.twelvemonkeys.imageio.metadata.Entry;
|
||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
||||
import com.twelvemonkeys.imageio.metadata.tiff.TIFF;
|
||||
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
@@ -158,21 +159,25 @@ class JPEGImage10Metadata extends AbstractMetadata {
|
||||
|
||||
case JPEG.DHT:
|
||||
HuffmanTable huffmanTable = (HuffmanTable) segment;
|
||||
IIOMetadataNode dht = new IIOMetadataNode("dht");
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
for (int c = 0; c < 2; c++) {
|
||||
if (huffmanTable.isPresent(i, c)) {
|
||||
IIOMetadataNode dhtable = new IIOMetadataNode("dhtable");
|
||||
dhtable.setAttribute("class", String.valueOf(c));
|
||||
dhtable.setAttribute("htableId", String.valueOf(i));
|
||||
dhtable.setUserObject(huffmanTable.toNativeTable(i, c));
|
||||
dht.appendChild(dhtable);
|
||||
}
|
||||
IIOMetadataNode dcTables = new IIOMetadataNode("dht");
|
||||
IIOMetadataNode acTables = new IIOMetadataNode("dht");
|
||||
|
||||
appendHuffmanTables(huffmanTable, 0, dcTables);
|
||||
appendHuffmanTables(huffmanTable, 1, acTables);
|
||||
|
||||
markerSequence.appendChild(dcTables);
|
||||
|
||||
// Native metadata has a limit of max 4 children of the DHT, we split by class only if we must...
|
||||
if (dcTables.getLength() + acTables.getLength() > 4) {
|
||||
markerSequence.appendChild(acTables);
|
||||
}
|
||||
else {
|
||||
while (acTables.hasChildNodes()) {
|
||||
dcTables.appendChild(acTables.removeChild(acTables.getFirstChild()));
|
||||
}
|
||||
}
|
||||
|
||||
markerSequence.appendChild(dht);
|
||||
break;
|
||||
|
||||
case JPEG.DQT:
|
||||
@@ -270,6 +275,18 @@ class JPEGImage10Metadata extends AbstractMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
private void appendHuffmanTables(HuffmanTable huffmanTable, int tableClass, IIOMetadataNode dht) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (huffmanTable.isPresent(i, tableClass)) {
|
||||
IIOMetadataNode dhtable = new IIOMetadataNode("dhtable");
|
||||
dhtable.setAttribute("class", String.valueOf(tableClass));
|
||||
dhtable.setAttribute("htableId", String.valueOf(i));
|
||||
dhtable.setUserObject(huffmanTable.toNativeTable(i, tableClass));
|
||||
dht.appendChild(dhtable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void appendICCProfile(IIOMetadataNode app0JFIF) {
|
||||
if (embeddedICCProfile != null) {
|
||||
IIOMetadataNode app2ICC = new IIOMetadataNode("app2ICC");
|
||||
|
||||
-345
@@ -1,345 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||
|
||||
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
|
||||
import com.twelvemonkeys.xml.XMLSerializer;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import javax.imageio.metadata.IIOInvalidTreeException;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.metadata.IIOMetadataNode;
|
||||
import java.awt.color.ICC_Profile;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* JPEGImage10MetadataCleaner
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: JPEGImage10MetadataCleaner.java,v 1.0 22.10.13 14:41 haraldk Exp$
|
||||
*/
|
||||
final class JPEGImage10MetadataCleaner {
|
||||
|
||||
private final JPEGImageReader reader;
|
||||
|
||||
JPEGImage10MetadataCleaner(final JPEGImageReader reader) {
|
||||
this.reader = reader;
|
||||
}
|
||||
|
||||
IIOMetadata cleanMetadata(final IIOMetadata imageMetadata) throws IOException {
|
||||
// We filter out pretty much everything from the stream..
|
||||
// Meaning we have to read get *all APP segments* and re-insert into metadata.
|
||||
List<Application> appSegments = reader.getAppSegments(JPEGImageReader.ALL_APP_MARKERS, null);
|
||||
|
||||
// NOTE: There's a bug in the merging code in JPEGMetadata mergeUnknownNode that makes sure all "unknown" nodes are added twice in certain conditions.... ARGHBL...
|
||||
// DONE: 1: Work around
|
||||
// TODO: 2: REPORT BUG!
|
||||
// TODO: Report dht inconsistency bug (reads any amount of tables but only allows setting 4 tables)
|
||||
|
||||
// TODO: Allow EXIF (as app1EXIF) in the JPEGvariety (sic) node. Need new format, might as well create a completely new format...
|
||||
// As EXIF is (a subset of) TIFF, (and the EXIF data is a valid TIFF stream) probably use something like:
|
||||
// http://download.java.net/media/jai-imageio/javadoc/1.1/com/sun/media/imageio/plugins/tiff/package-summary.html#ImageMetadata
|
||||
/*
|
||||
from: http://docs.oracle.com/javase/6/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html
|
||||
|
||||
In future versions of the JPEG metadata format, other varieties of JPEG metadata may be supported (e.g. Exif)
|
||||
by defining other types of nodes which may appear as a child of the JPEGvariety node.
|
||||
|
||||
(Note that an application wishing to interpret Exif metadata given a metadata tree structure in the
|
||||
javax_imageio_jpeg_image_1.0 format must check for an unknown marker segment with a tag indicating an
|
||||
APP1 marker and containing data identifying it as an Exif marker segment. Then it may use application-specific
|
||||
code to interpret the data in the marker segment. If such an application were to encounter a metadata tree
|
||||
formatted according to a future version of the JPEG metadata format, the Exif marker segment might not be
|
||||
unknown in that format - it might be structured as a child node of the JPEGvariety node.
|
||||
|
||||
Thus, it is important for an application to specify which version to use by passing the string identifying
|
||||
the version to the method/constructor used to obtain an IIOMetadata object.)
|
||||
*/
|
||||
|
||||
IIOMetadataNode tree = (IIOMetadataNode) imageMetadata.getAsTree(JPEGImage10Metadata.JAVAX_IMAGEIO_JPEG_IMAGE_1_0);
|
||||
IIOMetadataNode jpegVariety = (IIOMetadataNode) tree.getElementsByTagName("JPEGvariety").item(0);
|
||||
IIOMetadataNode markerSequence = (IIOMetadataNode) tree.getElementsByTagName("markerSequence").item(0);
|
||||
|
||||
JFIF jfifSegment = reader.getJFIF();
|
||||
JFXX jfxx = reader.getJFXX();
|
||||
AdobeDCT adobeDCT = reader.getAdobeDCT();
|
||||
ICC_Profile embeddedICCProfile = reader.getEmbeddedICCProfile(true);
|
||||
Frame sof = reader.getSOF();
|
||||
|
||||
boolean hasRealJFIF = false;
|
||||
boolean hasRealJFXX = false;
|
||||
boolean hasRealICC = false;
|
||||
|
||||
if (jfifSegment != null) {
|
||||
// Normal case, conformant JFIF with 1 or 3 components
|
||||
// TODO: Test if we have CMY or other non-JFIF color space?
|
||||
if (sof.componentsInFrame() == 1 || sof.componentsInFrame() == 3) {
|
||||
IIOMetadataNode jfif = new IIOMetadataNode("app0JFIF");
|
||||
jfif.setAttribute("majorVersion", String.valueOf(jfifSegment.majorVersion));
|
||||
jfif.setAttribute("minorVersion", String.valueOf(jfifSegment.minorVersion));
|
||||
jfif.setAttribute("resUnits", String.valueOf(jfifSegment.units));
|
||||
jfif.setAttribute("Xdensity", String.valueOf(Math.max(1, jfifSegment.xDensity))); // Avoid 0 density
|
||||
jfif.setAttribute("Ydensity", String.valueOf(Math.max(1,jfifSegment.yDensity)));
|
||||
jfif.setAttribute("thumbWidth", String.valueOf(jfifSegment.xThumbnail));
|
||||
jfif.setAttribute("thumbHeight", String.valueOf(jfifSegment.yThumbnail));
|
||||
|
||||
jpegVariety.appendChild(jfif);
|
||||
hasRealJFIF = true;
|
||||
|
||||
// Add app2ICC and JFXX as proper nodes
|
||||
if (embeddedICCProfile != null) {
|
||||
IIOMetadataNode app2ICC = new IIOMetadataNode("app2ICC");
|
||||
app2ICC.setUserObject(embeddedICCProfile);
|
||||
jfif.appendChild(app2ICC);
|
||||
hasRealICC = true;
|
||||
}
|
||||
|
||||
if (jfxx != null) {
|
||||
IIOMetadataNode JFXX = new IIOMetadataNode("JFXX");
|
||||
jfif.appendChild(JFXX);
|
||||
IIOMetadataNode app0JFXX = new IIOMetadataNode("app0JFXX");
|
||||
app0JFXX.setAttribute("extensionCode", String.valueOf(jfxx.extensionCode));
|
||||
|
||||
ThumbnailReader thumbnailReader = JFXXThumbnail.from(jfxx, reader.getThumbnailReader());
|
||||
IIOMetadataNode jfifThumb;
|
||||
|
||||
switch (jfxx.extensionCode) {
|
||||
case com.twelvemonkeys.imageio.plugins.jpeg.JFXX.JPEG:
|
||||
jfifThumb = new IIOMetadataNode("JFIFthumbJPEG");
|
||||
// Contains it's own "markerSequence" with full DHT, DQT, SOF etc...
|
||||
IIOMetadata thumbMeta = thumbnailReader.readMetadata();
|
||||
Node thumbTree = thumbMeta.getAsTree(JPEGImage10Metadata.JAVAX_IMAGEIO_JPEG_IMAGE_1_0);
|
||||
jfifThumb.appendChild(thumbTree.getLastChild());
|
||||
app0JFXX.appendChild(jfifThumb);
|
||||
break;
|
||||
|
||||
case com.twelvemonkeys.imageio.plugins.jpeg.JFXX.INDEXED:
|
||||
jfifThumb = new IIOMetadataNode("JFIFthumbPalette");
|
||||
jfifThumb.setAttribute("thumbWidth", String.valueOf(thumbnailReader.getWidth()));
|
||||
jfifThumb.setAttribute("thumbHeight", String.valueOf(thumbnailReader.getHeight()));
|
||||
app0JFXX.appendChild(jfifThumb);
|
||||
break;
|
||||
|
||||
case com.twelvemonkeys.imageio.plugins.jpeg.JFXX.RGB:
|
||||
jfifThumb = new IIOMetadataNode("JFIFthumbRGB");
|
||||
jfifThumb.setAttribute("thumbWidth", String.valueOf(thumbnailReader.getWidth()));
|
||||
jfifThumb.setAttribute("thumbHeight", String.valueOf(thumbnailReader.getHeight()));
|
||||
app0JFXX.appendChild(jfifThumb);
|
||||
break;
|
||||
|
||||
default:
|
||||
reader.processWarningOccurred(String.format("Unknown JFXX extension code: %d", jfxx.extensionCode));
|
||||
}
|
||||
|
||||
JFXX.appendChild(app0JFXX);
|
||||
hasRealJFXX = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Typically CMYK JPEG with JFIF segment (Adobe or similar).
|
||||
reader.processWarningOccurred(String.format(
|
||||
"Incompatible JFIF marker segment in stream. " +
|
||||
"SOF%d has %d color components, JFIF allows only 1 or 3 components. Ignoring JFIF marker.",
|
||||
sof.marker & 0xf, sof.componentsInFrame()
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Special case: Broken AdobeDCT segment, inconsistent with SOF, use values from SOF
|
||||
if (adobeDCT != null && (adobeDCT.transform == AdobeDCT.YCCK && sof.componentsInFrame() < 4 ||
|
||||
adobeDCT.transform == AdobeDCT.YCC && sof.componentsInFrame() < 3)) {
|
||||
reader.processWarningOccurred(String.format(
|
||||
"Invalid Adobe App14 marker. Indicates %s data, but SOF%d has %d color component(s). " +
|
||||
"Ignoring Adobe App14 marker.",
|
||||
adobeDCT.transform == AdobeDCT.YCCK ? "YCCK/CMYK" : "YCC/RGB",
|
||||
sof.marker & 0xf, sof.componentsInFrame()
|
||||
));
|
||||
|
||||
// Remove bad AdobeDCT
|
||||
NodeList app14Adobe = tree.getElementsByTagName("app14Adobe");
|
||||
for (int i = app14Adobe.getLength() - 1; i >= 0; i--) {
|
||||
Node item = app14Adobe.item(i);
|
||||
item.getParentNode().removeChild(item);
|
||||
}
|
||||
|
||||
// We don't add this as unknown marker, as we are certain it's bogus by now
|
||||
}
|
||||
|
||||
Node next = null;
|
||||
for (Application segment : appSegments) {
|
||||
// Except real app0JFIF, app0JFXX, app2ICC and app14Adobe, add all the app segments that we filtered away as "unknown" markers
|
||||
if (segment.marker == JPEG.APP0 && "JFIF".equals(segment.identifier) && hasRealJFIF) {
|
||||
continue;
|
||||
}
|
||||
else if (segment.marker == JPEG.APP0 && "JFXX".equals(segment.identifier) && hasRealJFXX) {
|
||||
continue;
|
||||
}
|
||||
else if (segment.marker == JPEG.APP1 && "Exif".equals(segment.identifier) /* always inserted */) {
|
||||
continue;
|
||||
}
|
||||
else if (segment.marker == JPEG.APP2 && "ICC_PROFILE".equals(segment.identifier) && hasRealICC) {
|
||||
continue;
|
||||
}
|
||||
else if (segment.marker == JPEG.APP14 && "Adobe".equals(segment.identifier) /* always inserted */) {
|
||||
continue;
|
||||
}
|
||||
|
||||
IIOMetadataNode unknown = new IIOMetadataNode("unknown");
|
||||
unknown.setAttribute("MarkerTag", Integer.toString(segment.marker & 0xff));
|
||||
|
||||
unknown.setUserObject(segment.data);
|
||||
|
||||
// try (DataInputStream stream = new DataInputStream(new ByteArrayInputStream(segment.data))) {
|
||||
// String identifier = segment.identifier;
|
||||
// int off = identifier != null ? identifier.length() + 1 : 0;
|
||||
//
|
||||
// byte[] data = new byte[off + segment.data.length];
|
||||
//
|
||||
// if (identifier != null) {
|
||||
// System.arraycopy(identifier.getBytes(Charset.forName("ASCII")), 0, data, 0, identifier.length());
|
||||
// }
|
||||
//
|
||||
// stream.readFully(data, off, segment.data.length);
|
||||
//
|
||||
// unknown.setUserObject(data);
|
||||
// }
|
||||
|
||||
if (next == null) {
|
||||
// To be semi-compatible with the functionality in mergeTree,
|
||||
// let's insert after the last unknown tag, or before any other tag if no unknown tag exists
|
||||
NodeList unknowns = markerSequence.getElementsByTagName("unknown");
|
||||
|
||||
if (unknowns.getLength() > 0) {
|
||||
next = unknowns.item(unknowns.getLength() - 1).getNextSibling();
|
||||
}
|
||||
else {
|
||||
next = markerSequence.getFirstChild();
|
||||
}
|
||||
}
|
||||
|
||||
markerSequence.insertBefore(unknown, next);
|
||||
}
|
||||
|
||||
// Known issues in the com.sun classes, if sof/sos component id or selector is negative,
|
||||
// setFromTree will fail. We'll fix the range from -128...127 to be 0...255.
|
||||
NodeList sofs = markerSequence.getElementsByTagName("sof");
|
||||
|
||||
if (sofs.getLength() > 0) {
|
||||
NodeList components = sofs.item(0).getChildNodes();
|
||||
for (int i = 0; i < components.getLength(); i++) {
|
||||
forceComponentIdInRange((IIOMetadataNode) components.item(i), "componentId");
|
||||
}
|
||||
}
|
||||
|
||||
NodeList sos = markerSequence.getElementsByTagName("sos");
|
||||
|
||||
for (int i = 0; i < sos.getLength(); i++) {
|
||||
NodeList specs = sos.item(i).getChildNodes();
|
||||
for (int j = 0; j < specs.getLength(); j++) {
|
||||
forceComponentIdInRange((IIOMetadataNode) specs.item(j), "componentSelector");
|
||||
}
|
||||
}
|
||||
|
||||
// Inconsistency issue in the com.sun classes, it can read metadata with dht containing
|
||||
// more than 4 children, but will not allow setting such a tree...
|
||||
// We'll split AC/DC tables into separate dht nodes.
|
||||
NodeList dhts = markerSequence.getElementsByTagName("dht");
|
||||
for (int j = 0; j < dhts.getLength(); j++) {
|
||||
Node dht = dhts.item(j);
|
||||
NodeList dhtables = dht.getChildNodes();
|
||||
|
||||
if (dhtables.getLength() < 1) {
|
||||
// Why is there an empty DHT node?
|
||||
dht.getParentNode().removeChild(dht);
|
||||
reader.processWarningOccurred("Metadata contains empty dht node. Ignoring.");
|
||||
}
|
||||
else if (dhtables.getLength() > 4) {
|
||||
IIOMetadataNode acTables = new IIOMetadataNode("dht");
|
||||
dht.getParentNode().insertBefore(acTables, dht.getNextSibling());
|
||||
|
||||
// Split into 2 dht nodes, one for AC and one for DC
|
||||
for (int i = dhtables.getLength() - 1; i >= 0 ; i--) {
|
||||
Element dhtable = (Element) dhtables.item(i);
|
||||
String tableClass = dhtable.getAttribute("class");
|
||||
if ("1".equals(tableClass)) {
|
||||
dht.removeChild(dhtable);
|
||||
acTables.insertBefore(dhtable, acTables.getFirstChild());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
imageMetadata.setFromTree(JPEGImage10Metadata.JAVAX_IMAGEIO_JPEG_IMAGE_1_0, tree);
|
||||
}
|
||||
catch (IIOInvalidTreeException e) {
|
||||
if (JPEGImageReader.DEBUG) {
|
||||
new XMLSerializer(System.out, System.getProperty("file.encoding")).serialize(imageMetadata.getAsTree(JPEGImage10Metadata.JAVAX_IMAGEIO_JPEG_IMAGE_1_0), false);
|
||||
System.out.println("-- 8< --");
|
||||
new XMLSerializer(System.out, System.getProperty("file.encoding")).serialize(tree, false);
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
|
||||
return imageMetadata;
|
||||
}
|
||||
|
||||
private void forceComponentIdInRange(final IIOMetadataNode component, final String attributeName) {
|
||||
String attribute = component.getAttribute(attributeName);
|
||||
|
||||
if (attribute != null) {
|
||||
try {
|
||||
int componentId = Integer.parseInt(attribute);
|
||||
|
||||
if (componentId < 0) {
|
||||
// Metadata doesn't like negative component ids/specs
|
||||
// We'll convert to the positive value it probably should have been
|
||||
componentId = ((byte) componentId) & 0xff;
|
||||
component.setAttribute(attributeName, String.valueOf(componentId));
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException ignore) {
|
||||
if ("scanComponentSpec".equals(component.getNodeName())) {
|
||||
reader.processWarningOccurred("Bad SOS component selector: " + attribute);
|
||||
}
|
||||
else {
|
||||
reader.processWarningOccurred("Bad SOF component id: " + attribute);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -104,6 +104,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
||||
// TODO: As we already parse the SOF segments, maybe we should stop delegating getWidth/getHeight etc?
|
||||
|
||||
final static boolean DEBUG = "true".equalsIgnoreCase(System.getProperty("com.twelvemonkeys.imageio.plugins.jpeg.debug"));
|
||||
final static boolean FORCE_RASTER_CONVERSION = "force".equalsIgnoreCase(System.getProperty("com.twelvemonkeys.imageio.plugins.jpeg.raster"));
|
||||
|
||||
/** Internal constant for referring all APP segments */
|
||||
static final int ALL_APP_MARKERS = -1;
|
||||
@@ -335,7 +336,7 @@ public final class JPEGImageReader extends ImageReaderBase {
|
||||
|
||||
// We need to apply ICC profile unless the profile is sRGB/default gray (whatever that is)
|
||||
// - or only filter out the bad ICC profiles in the JPEGSegmentImageInputStream.
|
||||
else if (bogusAdobeDCT
|
||||
else if (FORCE_RASTER_CONVERSION || bogusAdobeDCT
|
||||
|| profile != null && !ColorProfiles.isCS_sRGB(profile)
|
||||
|| (long) sof.lines * sof.samplesPerLine > Integer.MAX_VALUE
|
||||
|| delegateCSTypeMismatch(jfif, adobeDCT, sof, sourceCSType)) {
|
||||
|
||||
+15
-12
@@ -31,6 +31,7 @@
|
||||
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||
|
||||
import com.twelvemonkeys.imageio.stream.URLImageInputStreamSpi;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NodeList;
|
||||
@@ -42,6 +43,7 @@ import javax.imageio.metadata.IIOMetadataNode;
|
||||
import javax.imageio.spi.IIORegistry;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@@ -50,14 +52,13 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* JPEGImage10MetadataCleanerTest.
|
||||
* JPEGImage10MetadataTest.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: harald.kuhr$
|
||||
* @version $Id: JPEGImage10MetadataCleanerTest.java,v 1.0 08/08/16 harald.kuhr Exp$
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: JPEGImage10MetadataTest.java,v 1.0 12/01/2022 haraldk Exp$
|
||||
*/
|
||||
public class JPEGImage10MetadataCleanerTest {
|
||||
|
||||
public class JPEGImage10MetadataTest {
|
||||
static {
|
||||
IIORegistry.getDefaultInstance().registerServiceProvider(new URLImageInputStreamSpi());
|
||||
ImageIO.setUseCache(false);
|
||||
@@ -69,14 +70,14 @@ public class JPEGImage10MetadataCleanerTest {
|
||||
return lookupProviderByName(IIORegistry.getDefaultInstance(), "com.sun.imageio.plugins.jpeg.JPEGImageReaderSpi", ImageReaderSpi.class);
|
||||
}
|
||||
|
||||
// Unit/regression test for #276
|
||||
// Unit/regression test for #276, #559
|
||||
@Test
|
||||
public void cleanMetadataMoreThan4DHTSegments() throws Exception {
|
||||
public void splitMoreThan4DHTSegments() throws Exception {
|
||||
List<String> testData = Arrays.asList("/jpeg/5dhtsegments.jpg", "/jpeg/6dhtsegments.jpg");
|
||||
|
||||
for (String data : testData) {
|
||||
try (ImageInputStream origInput = ImageIO.createImageInputStream(getClass().getResource(data));
|
||||
ImageInputStream input = ImageIO.createImageInputStream(getClass().getResource(data))) {
|
||||
try (ImageInputStream origInput = ImageIO.createImageInputStream(getClassResource(data));
|
||||
ImageInputStream input = ImageIO.createImageInputStream(getClassResource(data))) {
|
||||
|
||||
ImageReader origReader = SPI.delegateProvider.createReaderInstance();
|
||||
origReader.setInput(origInput);
|
||||
@@ -87,9 +88,7 @@ public class JPEGImage10MetadataCleanerTest {
|
||||
IIOMetadata original = origReader.getImageMetadata(0);
|
||||
IIOMetadataNode origTree = (IIOMetadataNode) original.getAsTree(JPEGImage10Metadata.JAVAX_IMAGEIO_JPEG_IMAGE_1_0);
|
||||
|
||||
JPEGImage10MetadataCleaner cleaner = new JPEGImage10MetadataCleaner((JPEGImageReader) reader);
|
||||
IIOMetadata cleaned = cleaner.cleanMetadata(origReader.getImageMetadata(0));
|
||||
|
||||
JPEGImage10Metadata cleaned = (JPEGImage10Metadata) reader.getImageMetadata(0);
|
||||
IIOMetadataNode cleanTree = (IIOMetadataNode) cleaned.getAsTree(JPEGImage10Metadata.JAVAX_IMAGEIO_JPEG_IMAGE_1_0);
|
||||
|
||||
NodeList origDHT = origTree.getElementsByTagName("dht");
|
||||
@@ -124,4 +123,8 @@ public class JPEGImage10MetadataCleanerTest {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private URL getClassResource(String name) {
|
||||
return getClass().getResource(name);
|
||||
}
|
||||
}
|
||||
+36
-33
@@ -30,34 +30,15 @@
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.jpeg;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import com.twelvemonkeys.imageio.color.ColorSpaces;
|
||||
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||
import com.twelvemonkeys.imageio.util.ImageWriterAbstractTest;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.color.ICC_Profile;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.ComponentColorModel;
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import org.junit.Test;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import javax.imageio.IIOImage;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.ImageWriteParam;
|
||||
import javax.imageio.ImageWriter;
|
||||
import javax.imageio.*;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
||||
import javax.imageio.metadata.IIOMetadataNode;
|
||||
@@ -66,14 +47,22 @@ import javax.imageio.spi.ImageWriterSpi;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import javax.imageio.stream.ImageOutputStream;
|
||||
import javax.imageio.stream.MemoryCacheImageOutputStream;
|
||||
import java.awt.*;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.color.ICC_Profile;
|
||||
import java.awt.image.*;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import com.twelvemonkeys.imageio.color.ColorSpaces;
|
||||
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||
import com.twelvemonkeys.imageio.util.ImageWriterAbstractTest;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* JPEGImageWriterTest
|
||||
@@ -161,6 +150,20 @@ public class JPEGImageWriterTest extends ImageWriterAbstractTest<JPEGImageWriter
|
||||
}
|
||||
}
|
||||
|
||||
// Unit/regression test for #559
|
||||
@Test
|
||||
public void testTranscodeMoreThan4DHTSegments() throws IOException {
|
||||
ImageWriter writer = createWriter();
|
||||
ImageReader reader = ImageIO.getImageReader(writer);
|
||||
|
||||
ByteArrayOutputStream stream = transcode(reader, getClassLoaderResource("/jpeg/5dhtsegments.jpg"), writer, ColorSpace.TYPE_RGB);
|
||||
|
||||
reader.reset();
|
||||
reader.setInput(new ByteArrayImageInputStream(stream.toByteArray()));
|
||||
BufferedImage image = reader.read(0);
|
||||
assertNotNull(image);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTranscodeWithMetadataRGBtoRGB() throws IOException {
|
||||
ImageWriter writer = createWriter();
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<version>3.8.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>imageio-metadata</artifactId>
|
||||
|
||||
+4
@@ -173,10 +173,14 @@ public final class TIFFEntry extends AbstractEntry {
|
||||
return "TileByteCounts";
|
||||
case TIFF.TAG_COPYRIGHT:
|
||||
return "Copyright";
|
||||
case TIFF.TAG_YCBCR_COEFFICIENTS:
|
||||
return "YCbCrCoefficients";
|
||||
case TIFF.TAG_YCBCR_SUB_SAMPLING:
|
||||
return "YCbCrSubSampling";
|
||||
case TIFF.TAG_YCBCR_POSITIONING:
|
||||
return "YCbCrPositioning";
|
||||
case TIFF.TAG_REFERENCE_BLACK_WHITE:
|
||||
return "ReferenceBlackWhite";
|
||||
case TIFF.TAG_COLOR_MAP:
|
||||
return "ColorMap";
|
||||
case TIFF.TAG_INK_SET:
|
||||
|
||||
+45
-17
@@ -80,7 +80,7 @@ public final class TIFFReader extends MetadataReader {
|
||||
|
||||
private final Set<Long> parsedIFDs = new TreeSet<>();
|
||||
|
||||
private long length;
|
||||
private long inputLength;
|
||||
private boolean longOffsets;
|
||||
private int offsetSize;
|
||||
|
||||
@@ -127,7 +127,7 @@ public final class TIFFReader extends MetadataReader {
|
||||
throw new IIOException(String.format("Wrong TIFF magic in input data: %04x, expected: %04x", magic, TIFF.TIFF_MAGIC));
|
||||
}
|
||||
|
||||
length = input.length();
|
||||
inputLength = input.length();
|
||||
|
||||
return readLinkedIFDs(input);
|
||||
}
|
||||
@@ -140,7 +140,7 @@ public final class TIFFReader extends MetadataReader {
|
||||
// Read linked IFDs
|
||||
while (ifdOffset != 0) {
|
||||
try {
|
||||
if ((length > 0 && ifdOffset >= length) || !parsedIFDs.add(ifdOffset)) {
|
||||
if ((inputLength > 0 && ifdOffset >= inputLength) || !isValidOffset(input, ifdOffset) || !parsedIFDs.add(ifdOffset)) {
|
||||
// TODO: Issue warning
|
||||
if (DEBUG) {
|
||||
System.err.println("Bad IFD offset: " + ifdOffset);
|
||||
@@ -218,7 +218,7 @@ public final class TIFFReader extends MetadataReader {
|
||||
|
||||
for (long ifdOffset : ifdOffsets) {
|
||||
try {
|
||||
if ((length > 0 && ifdOffset >= length) || !parsedIFDs.add(ifdOffset)) {
|
||||
if ((inputLength > 0 && ifdOffset >= inputLength) || !isValidOffset(input, ifdOffset) || !parsedIFDs.add(ifdOffset)) {
|
||||
// TODO: Issue warning
|
||||
if (DEBUG) {
|
||||
System.err.println("Bad IFD offset: " + ifdOffset);
|
||||
@@ -330,20 +330,14 @@ public final class TIFFReader extends MetadataReader {
|
||||
long valueLength = getValueLength(type, count);
|
||||
|
||||
Object value;
|
||||
|
||||
if (valueLength > 0 && valueLength <= offsetSize) {
|
||||
value = readValueInLine(pInput, type, count);
|
||||
pInput.skipBytes(offsetSize - valueLength);
|
||||
}
|
||||
else {
|
||||
long valueOffset = readOffset(pInput); // This is the *value* iff the value size is <= offsetSize
|
||||
|
||||
// Note: This a precaution
|
||||
if (count >= Integer.MAX_VALUE || length > 0 && length < valueOffset + valueLength) {
|
||||
value = new EOFException(String.format("TIFF value offset or size too large: %d/%d bytes (length: %d bytes)", valueOffset, valueLength, length));
|
||||
}
|
||||
else {
|
||||
value = readValueAt(pInput, valueOffset, type, count);
|
||||
}
|
||||
value = readValueAt(pInput, valueOffset, valueLength, type, count);
|
||||
}
|
||||
|
||||
return new TIFFEntry(tagId, type, value);
|
||||
@@ -365,18 +359,52 @@ public final class TIFFReader extends MetadataReader {
|
||||
return (int) count;
|
||||
}
|
||||
|
||||
private Object readValueAt(final ImageInputStream pInput, final long pOffset, final short pType, final int pCount) throws IOException {
|
||||
long pos = pInput.getStreamPosition();
|
||||
private boolean isValidOffset(final ImageInputStream input, final long pos) throws IOException {
|
||||
// TODO: If the position returns false, we could limit the length to pos for further reads...
|
||||
try {
|
||||
pInput.seek(pOffset);
|
||||
return readValue(pInput, pType, pCount, longOffsets);
|
||||
input.mark();
|
||||
input.seek(pos);
|
||||
|
||||
return input.read() >= 0;
|
||||
}
|
||||
catch (IOException e) {
|
||||
return false;
|
||||
}
|
||||
finally {
|
||||
input.reset();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValidLengthAtOffset(final ImageInputStream input, long offset, long valueLength) throws IOException {
|
||||
// NOTE: For values smaller than Short.MAX_VALUE, we simply try, and handle the potential EOFException when reading
|
||||
return (inputLength < 0 || inputLength >= offset + valueLength)
|
||||
&& (valueLength < Short.MAX_VALUE || isValidOffset(input, offset + valueLength - 1));
|
||||
}
|
||||
|
||||
private Object readValueAt(final ImageInputStream input, final long offset, final long length, final short type, final int count) throws IOException {
|
||||
long pos = input.getStreamPosition();
|
||||
|
||||
try {
|
||||
input.seek(offset);
|
||||
|
||||
// Avoid OOME due to corrupted/malicious data
|
||||
if (count < Integer.MAX_VALUE && isValidLengthAtOffset(input, offset, length)) {
|
||||
return readValue(input, type, count, longOffsets);
|
||||
}
|
||||
else {
|
||||
throw new EOFException(String.format("TIFF value offset or size too large: @%08x/%d bytes (input length: %s)", offset, length, inputLength >= 0 ? inputLength + " bytes" : "unknown"));
|
||||
}
|
||||
}
|
||||
catch (EOFException e) {
|
||||
// TODO: Add warning listener API and report problem to client code
|
||||
if (DEBUG) {
|
||||
System.err.println(e);
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
finally {
|
||||
pInput.seek(pos);
|
||||
input.seek(pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+31
-5
@@ -292,7 +292,26 @@ public final class TIFFWriter extends MetadataWriter {
|
||||
|
||||
private int getCount(final Entry entry) {
|
||||
Object value = entry.getValue();
|
||||
return value instanceof String ? ((String) value).getBytes(StandardCharsets.UTF_8).length + 1 : entry.valueCount();
|
||||
|
||||
if (value instanceof String) {
|
||||
return computeStringLength((String) value);
|
||||
}
|
||||
else if (value instanceof String[]) {
|
||||
return computeStringLength((String[]) value);
|
||||
}
|
||||
else {
|
||||
return entry.valueCount();
|
||||
}
|
||||
}
|
||||
|
||||
private int computeStringLength(String... values) {
|
||||
int sum = 0;
|
||||
|
||||
for (String value : values) {
|
||||
sum += value.getBytes(StandardCharsets.UTF_8).length + 1;
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
private void writeValueInline(final Object value, final short type, final ImageOutputStream stream) throws IOException {
|
||||
@@ -410,7 +429,9 @@ public final class TIFFWriter extends MetadataWriter {
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case TIFF.TYPE_ASCII:
|
||||
writeStrings(stream, (String[]) value);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported TIFF type: " + type);
|
||||
}
|
||||
@@ -423,9 +444,7 @@ public final class TIFFWriter extends MetadataWriter {
|
||||
stream.writeByte(((Number) value).intValue());
|
||||
break;
|
||||
case TIFF.TYPE_ASCII:
|
||||
byte[] bytes = ((String) value).getBytes(StandardCharsets.UTF_8);
|
||||
stream.write(bytes);
|
||||
stream.write(0);
|
||||
writeStrings(stream, (String) value);
|
||||
break;
|
||||
case TIFF.TYPE_SHORT:
|
||||
case TIFF.TYPE_SSHORT:
|
||||
@@ -462,6 +481,13 @@ public final class TIFFWriter extends MetadataWriter {
|
||||
}
|
||||
}
|
||||
|
||||
private void writeStrings(ImageOutputStream stream, String... values) throws IOException {
|
||||
for (String value : values) {
|
||||
stream.write(value.getBytes(StandardCharsets.UTF_8));
|
||||
stream.write(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeValueAt(final long dataOffset, final Object value, final short type, final ImageOutputStream stream) throws IOException {
|
||||
writeOffset(stream, dataOffset);
|
||||
long position = stream.getStreamPosition();
|
||||
|
||||
+6
-6
@@ -1,16 +1,16 @@
|
||||
package com.twelvemonkeys.imageio.metadata.tiff;
|
||||
|
||||
import com.twelvemonkeys.io.FastByteArrayOutputStream;
|
||||
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.Random;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.twelvemonkeys.io.FastByteArrayOutputStream;
|
||||
|
||||
/**
|
||||
* HalfTest.
|
||||
@@ -97,7 +97,7 @@ public class HalfTest {
|
||||
}
|
||||
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void testParseHAlfNull() {
|
||||
public void testParseHalfNull() {
|
||||
Half.parseHalf(null);
|
||||
}
|
||||
|
||||
|
||||
+47
-25
@@ -47,8 +47,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* TIFFWriterTest
|
||||
@@ -84,11 +83,13 @@ public class TIFFWriterTest extends MetadataWriterAbstractTest {
|
||||
Directory directory = new AbstractDirectory(entries) {};
|
||||
|
||||
ByteArrayOutputStream output = new FastByteArrayOutputStream(1024);
|
||||
ImageOutputStream imageStream = ImageIO.createImageOutputStream(output);
|
||||
createWriter().write(directory, imageStream);
|
||||
imageStream.flush();
|
||||
|
||||
assertEquals(output.size(), imageStream.getStreamPosition());
|
||||
try (ImageOutputStream imageStream = ImageIO.createImageOutputStream(output)) {
|
||||
createWriter().write(directory, imageStream);
|
||||
imageStream.flush();
|
||||
|
||||
assertEquals(output.size(), imageStream.getStreamPosition());
|
||||
}
|
||||
|
||||
byte[] data = output.toByteArray();
|
||||
|
||||
@@ -129,14 +130,15 @@ public class TIFFWriterTest extends MetadataWriterAbstractTest {
|
||||
Directory directory = new AbstractDirectory(entries) {};
|
||||
|
||||
ByteArrayOutputStream output = new FastByteArrayOutputStream(1024);
|
||||
ImageOutputStream imageStream = ImageIO.createImageOutputStream(output);
|
||||
|
||||
imageStream.setByteOrder(ByteOrder.BIG_ENDIAN); // BE = Motorola
|
||||
try (ImageOutputStream imageStream = ImageIO.createImageOutputStream(output)) {
|
||||
imageStream.setByteOrder(ByteOrder.BIG_ENDIAN); // BE = Motorola
|
||||
|
||||
createWriter().write(directory, imageStream);
|
||||
imageStream.flush();
|
||||
createWriter().write(directory, imageStream);
|
||||
imageStream.flush();
|
||||
|
||||
assertEquals(output.size(), imageStream.getStreamPosition());
|
||||
assertEquals(output.size(), imageStream.getStreamPosition());
|
||||
}
|
||||
|
||||
byte[] data = output.toByteArray();
|
||||
|
||||
@@ -164,14 +166,15 @@ public class TIFFWriterTest extends MetadataWriterAbstractTest {
|
||||
Directory directory = new AbstractDirectory(entries) {};
|
||||
|
||||
ByteArrayOutputStream output = new FastByteArrayOutputStream(1024);
|
||||
ImageOutputStream imageStream = ImageIO.createImageOutputStream(output);
|
||||
|
||||
imageStream.setByteOrder(ByteOrder.LITTLE_ENDIAN); // LE = Intel
|
||||
try (ImageOutputStream imageStream = ImageIO.createImageOutputStream(output)) {
|
||||
imageStream.setByteOrder(ByteOrder.LITTLE_ENDIAN); // LE = Intel
|
||||
|
||||
createWriter().write(directory, imageStream);
|
||||
imageStream.flush();
|
||||
createWriter().write(directory, imageStream);
|
||||
imageStream.flush();
|
||||
|
||||
assertEquals(output.size(), imageStream.getStreamPosition());
|
||||
assertEquals(output.size(), imageStream.getStreamPosition());
|
||||
}
|
||||
|
||||
byte[] data = output.toByteArray();
|
||||
|
||||
@@ -203,12 +206,13 @@ public class TIFFWriterTest extends MetadataWriterAbstractTest {
|
||||
Directory directory = new IFD(Collections.<Entry>singletonList(subIFD));
|
||||
|
||||
ByteArrayOutputStream output = new FastByteArrayOutputStream(1024);
|
||||
ImageOutputStream imageStream = ImageIO.createImageOutputStream(output);
|
||||
|
||||
createWriter().write(directory, imageStream);
|
||||
imageStream.flush();
|
||||
try (ImageOutputStream imageStream = ImageIO.createImageOutputStream(output)) {
|
||||
createWriter().write(directory, imageStream);
|
||||
imageStream.flush();
|
||||
|
||||
assertEquals(output.size(), imageStream.getStreamPosition());
|
||||
assertEquals(output.size(), imageStream.getStreamPosition());
|
||||
}
|
||||
|
||||
Directory read = new TIFFReader().read(new ByteArrayImageInputStream(output.toByteArray()));
|
||||
|
||||
@@ -222,14 +226,10 @@ public class TIFFWriterTest extends MetadataWriterAbstractTest {
|
||||
Directory original = createReader().read(getDataAsIIS());
|
||||
|
||||
ByteArrayOutputStream output = new FastByteArrayOutputStream(256);
|
||||
ImageOutputStream imageOutput = ImageIO.createImageOutputStream(output);
|
||||
|
||||
try {
|
||||
try (ImageOutputStream imageOutput = ImageIO.createImageOutputStream(output)) {
|
||||
createWriter().write(original, imageOutput);
|
||||
}
|
||||
finally {
|
||||
imageOutput.close();
|
||||
}
|
||||
|
||||
Directory read = createReader().read(new ByteArrayImageInputStream(output.toByteArray()));
|
||||
|
||||
@@ -254,6 +254,28 @@ public class TIFFWriterTest extends MetadataWriterAbstractTest {
|
||||
assertEquals(98, stream.getStreamPosition());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteASCIIArray() throws IOException {
|
||||
ArrayList<Entry> entries = new ArrayList<>();
|
||||
String[] strings = new String [] {"Twelve", "Monkeys", "ImageIO"};
|
||||
entries.add(new TIFFEntry(TIFF.TAG_SOFTWARE, strings));
|
||||
Directory directory = new IFD(entries);
|
||||
|
||||
ByteArrayOutputStream output = new FastByteArrayOutputStream(1024);
|
||||
|
||||
try (ImageOutputStream imageStream = ImageIO.createImageOutputStream(output)) {
|
||||
imageStream.setByteOrder(ByteOrder.LITTLE_ENDIAN); // LE = Intel
|
||||
createWriter().write(directory, imageStream);
|
||||
}
|
||||
|
||||
byte[] data = output.toByteArray();
|
||||
Directory read = new TIFFReader().read(new ByteArrayImageInputStream(data));
|
||||
|
||||
assertNotNull(read.getEntryById(TIFF.TAG_SOFTWARE));
|
||||
assertTrue("value not an string array", read.getEntryById(TIFF.TAG_SOFTWARE).getValue() instanceof String[]);
|
||||
assertArrayEquals(strings, (String[]) read.getEntryById(TIFF.TAG_SOFTWARE).getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComputeIFDSizeNested() throws IOException {
|
||||
TIFFEntry artist = new TIFFEntry(TIFF.TAG_SOFTWARE, TIFF.TYPE_ASCII, "TwelveMonkeys ImageIO");
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.8.0</version>
|
||||
<version>3.8.3</version>
|
||||
</parent>
|
||||
<artifactId>imageio-pcx</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: PCX plugin</name>
|
||||
|
||||
+7
-10
@@ -140,10 +140,9 @@ public final class PCXImageReader extends ImageReaderBase {
|
||||
if (palette != null) {
|
||||
return ImageTypeSpecifiers.createFromIndexColorModel(palette);
|
||||
}
|
||||
else {
|
||||
// PCX Gray has 1 channel and no palette
|
||||
return ImageTypeSpecifiers.createGrayscale(8, DataBuffer.TYPE_BYTE);
|
||||
}
|
||||
|
||||
// PCX Gray has 1 channel and no palette
|
||||
return ImageTypeSpecifiers.createGrayscale(8, DataBuffer.TYPE_BYTE);
|
||||
}
|
||||
|
||||
// PCX RGB has channels for 24 bit RGB, will be validated by ImageTypeSpecifier
|
||||
@@ -214,14 +213,12 @@ public final class PCXImageReader extends ImageReaderBase {
|
||||
byte[] rowDataByte = ((DataBufferByte) rowRaster.getDataBuffer()).getData();
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
switch (header.getBitsPerPixel()) {
|
||||
case 1:
|
||||
readRowByte(input, srcRegion, xSub, ySub, planeData, 0, planeWidth * header.getChannels(), destRaster, clippedRow, y);
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
if (header.getBitsPerPixel() != 1) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
readRowByte(input, srcRegion, xSub, ySub, planeData, 0, planeWidth * header.getChannels(), destRaster, clippedRow, y);
|
||||
|
||||
int pixelPos = 0;
|
||||
for (int planePos = 0; planePos < planeWidth; planePos++) {
|
||||
BitRotator.bitRotateCW(planeData, planePos, planeWidth, rowDataByte, pixelPos, 1);
|
||||
|
||||
+9
-15
@@ -64,17 +64,10 @@ public class PCXImageReaderTest extends ImageReaderAbstractTest<PCXImageReader>
|
||||
@Override
|
||||
protected List<TestData> getTestData() {
|
||||
return Arrays.asList(
|
||||
new TestData(getClassLoaderResource("/pcx/input.pcx"), new Dimension(70, 46)), // RLE encoded RGB
|
||||
new TestData(getClassLoaderResource("/pcx/lena.pcx"), new Dimension(512, 512)), // RLE encoded RGB
|
||||
new TestData(getClassLoaderResource("/pcx/lena2.pcx"), new Dimension(512, 512)), // RLE encoded, 256 color indexed (8 bps/1 channel)
|
||||
new TestData(getClassLoaderResource("/pcx/lena3.pcx"), new Dimension(512, 512)), // RLE encoded, 16 color indexed (4 bps/1 channel)
|
||||
new TestData(getClassLoaderResource("/pcx/lena4.pcx"), new Dimension(512, 512)), // RLE encoded, 16 color indexed (1 bps/4 channels)
|
||||
new TestData(getClassLoaderResource("/pcx/lena5.pcx"), new Dimension(512, 512)), // RLE encoded, 256 color indexed (8 bps/1 channel)
|
||||
new TestData(getClassLoaderResource("/pcx/lena6.pcx"), new Dimension(512, 512)), // RLE encoded, 8 color indexed (1 bps/3 channels)
|
||||
new TestData(getClassLoaderResource("/pcx/lena7.pcx"), new Dimension(512, 512)), // RLE encoded, 4 color indexed (1 bps/2 channels)
|
||||
new TestData(getClassLoaderResource("/pcx/lena8.pcx"), new Dimension(512, 512)), // RLE encoded, 4 color indexed (2 bps/1 channel)
|
||||
new TestData(getClassLoaderResource("/pcx/lena9.pcx"), new Dimension(512, 512)), // RLE encoded, 2 color indexed (1 bps/1 channel)
|
||||
new TestData(getClassLoaderResource("/pcx/lena10.pcx"), new Dimension(512, 512)), // RLE encoded, 16 color indexed (4 bps/1 channel) (uses only 8 colors)
|
||||
new TestData(getClassLoaderResource("/pcx/input.pcx"), new Dimension(70, 46)), // RLE encoded RGB, v5
|
||||
new TestData(getClassLoaderResource("/pcx/rose.pcx"), new Dimension(38, 48)), // RLE encoded, 16 color indexed (1 bps/4 channels), v5
|
||||
new TestData(getClassLoaderResource("/pcx/animals.pcx"), new Dimension(239, 157)), // RLE encoded, 8 color indexed (1 bps/3 channels), v3
|
||||
// TODO: Find good test images for the various combinations of bits/sample & channels
|
||||
new TestData(getClassLoaderResource("/pcx/DARKSTAR.PCX"), new Dimension(88, 52)), // RLE encoded monochrome (1 bps/1 channel)
|
||||
new TestData(getClassLoaderResource("/pcx/MARBLES.PCX"), new Dimension(1419, 1001)), // RLE encoded RGB
|
||||
new TestData(getClassLoaderResource("/pcx/no-palette-monochrome.pcx"), new Dimension(128, 152)), // RLE encoded monochrome (1 bps/1 channel)
|
||||
@@ -149,11 +142,12 @@ public class PCXImageReaderTest extends ImageReaderAbstractTest<PCXImageReader>
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Test
|
||||
public void testReadWithSourceRegionParamEqualImage() throws IOException {
|
||||
TestData data = getTestData().get(1);
|
||||
assertReadWithSourceRegionParamEqualImage(new Rectangle(200, 0, 4, 4), data, 0);
|
||||
assertReadWithSourceRegionParamEqualImage(new Rectangle(100, 100, 4, 4), data, 0);
|
||||
assertReadWithSourceRegionParamEqualImage(new Rectangle(0, 200, 4, 4), data, 0);
|
||||
TestData data = getTestData().get(0);
|
||||
assertReadWithSourceRegionParamEqualImage(new Rectangle(66, 0, 4, 4), data, 0);
|
||||
assertReadWithSourceRegionParamEqualImage(new Rectangle(32, 20, 4, 4), data, 0);
|
||||
assertReadWithSourceRegionParamEqualImage(new Rectangle(0, 42, 4, 4), data, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user