mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2026-05-20 00:00:03 -04:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fe591d9b6c | |||
| 06d988377e | |||
| 360b4e9bba |
@@ -5,13 +5,9 @@ updates:
|
|||||||
directory: "/"
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
interval: "daily"
|
interval: "daily"
|
||||||
cooldown:
|
|
||||||
default-days: 7
|
|
||||||
open-pull-requests-limit: 10
|
open-pull-requests-limit: 10
|
||||||
# GitHub actions updates
|
# GitHub actions updates
|
||||||
- package-ecosystem: "github-actions"
|
- package-ecosystem: "github-actions"
|
||||||
directory: "/.github/workflows"
|
directory: "/.github/workflows"
|
||||||
schedule:
|
schedule:
|
||||||
interval: "daily"
|
interval: "daily"
|
||||||
cooldown:
|
|
||||||
default-days: 7
|
|
||||||
|
|||||||
+24
-40
@@ -17,16 +17,13 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ ubuntu-latest, windows-latest, macos-latest ]
|
os: [ ubuntu-latest, windows-latest, macos-latest ]
|
||||||
java: [ 8, 11, 17, 21, 25 ]
|
java: [ 11, 17, 21, 23 ]
|
||||||
exclude:
|
|
||||||
- os: macos-latest
|
|
||||||
java: 8
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
permissions:
|
permissions:
|
||||||
checks: write
|
checks: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
|
||||||
with:
|
with:
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
java-version: ${{ matrix.java }}
|
java-version: ${{ matrix.java }}
|
||||||
@@ -35,29 +32,33 @@ jobs:
|
|||||||
- name: Run Tests
|
- name: Run Tests
|
||||||
run: mvn --batch-mode --no-transfer-progress test
|
run: mvn --batch-mode --no-transfer-progress test
|
||||||
- name: Publish Test Report
|
- name: Publish Test Report
|
||||||
uses: mikepenz/action-junit-report@bccf2e31636835cf0874589931c4116687171386 # v5
|
uses: mikepenz/action-junit-report@65fe03598d8d251738592a497a9e8547a5c48eaa # v5
|
||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
with:
|
with:
|
||||||
report_paths: "**/target/surefire-reports/TEST*.xml"
|
report_paths: "**/target/surefire-reports/TEST*.xml"
|
||||||
check_name: Unit Test Results for OpenJDK ${{ matrix.java }} on ${{ matrix.os }}
|
check_name: Unit Test Results for OpenJDK ${{ matrix.java }} on ${{ matrix.os }}
|
||||||
|
|
||||||
test-jdk8-macos:
|
test-jdk8:
|
||||||
name: Test OpenJDK 8 on macos-14
|
name: Test OpenJDK ${{ matrix.java }} on ${{ matrix.os }}
|
||||||
runs-on: macos-14
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
os: [ ubuntu-latest, windows-latest, macos-13 ]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
permissions:
|
permissions:
|
||||||
checks: write
|
checks: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
|
||||||
with:
|
with:
|
||||||
distribution: 'zulu'
|
distribution: 'temurin'
|
||||||
java-version: '8'
|
java-version: '8'
|
||||||
java-package: jdk
|
java-package: jdk
|
||||||
cache: 'maven'
|
cache: 'maven'
|
||||||
- name: Run Tests
|
- name: Run Tests
|
||||||
run: mvn --batch-mode --no-transfer-progress test
|
run: mvn --batch-mode --no-transfer-progress test
|
||||||
- name: Publish Test Report
|
- name: Publish Test Report
|
||||||
uses: mikepenz/action-junit-report@bccf2e31636835cf0874589931c4116687171386 # v5
|
uses: mikepenz/action-junit-report@65fe03598d8d251738592a497a9e8547a5c48eaa # v5
|
||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
with:
|
with:
|
||||||
report_paths: "**/target/surefire-reports/TEST*.xml"
|
report_paths: "**/target/surefire-reports/TEST*.xml"
|
||||||
@@ -72,11 +73,11 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
kcms: [ true, false ]
|
kcms: [ true, false ]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- run: |
|
- run: |
|
||||||
download_url="https://javadl.oracle.com/webapps/download/AutoDL?BundleId=245038_d3c52aa6bfa54d3ca74e617f18309292"
|
download_url="https://javadl.oracle.com/webapps/download/AutoDL?BundleId=245038_d3c52aa6bfa54d3ca74e617f18309292"
|
||||||
wget -O $RUNNER_TEMP/java_package.tar.gz $download_url
|
wget -O $RUNNER_TEMP/java_package.tar.gz $download_url
|
||||||
- uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
- uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
|
||||||
with:
|
with:
|
||||||
distribution: 'jdkfile'
|
distribution: 'jdkfile'
|
||||||
jdkFile: ${{ runner.temp }}/java_package.tar.gz
|
jdkFile: ${{ runner.temp }}/java_package.tar.gz
|
||||||
@@ -91,43 +92,26 @@ jobs:
|
|||||||
- name: Run Tests
|
- name: Run Tests
|
||||||
run: mvn --batch-mode --no-transfer-progress test
|
run: mvn --batch-mode --no-transfer-progress test
|
||||||
- name: Publish Test Report
|
- name: Publish Test Report
|
||||||
uses: mikepenz/action-junit-report@bccf2e31636835cf0874589931c4116687171386 # v5
|
uses: mikepenz/action-junit-report@65fe03598d8d251738592a497a9e8547a5c48eaa # v5
|
||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
with:
|
with:
|
||||||
report_paths: "**/target/surefire-reports/TEST*.xml"
|
report_paths: "**/target/surefire-reports/TEST*.xml"
|
||||||
check_name: Unit Test Results for Oracle JDK 8 with KCMS=${{ matrix.kcms }}
|
check_name: Unit Test Results for Oracle JDK 8 with KCMS=${{ matrix.kcms }}
|
||||||
|
|
||||||
javadoc:
|
|
||||||
name: Build JavaDoc on OpenJDK ${{ matrix.java }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
java: [8, 11, 25 ] # We only need a few versions here
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
||||||
- uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
|
||||||
with:
|
|
||||||
distribution: 'temurin'
|
|
||||||
java-version: ${{ matrix.java }}
|
|
||||||
java-package: jdk
|
|
||||||
cache: 'maven'
|
|
||||||
- name: Create JavaDoc
|
|
||||||
run: mvn --batch-mode --no-transfer-progress -DskipTests package javadoc:javadoc
|
|
||||||
|
|
||||||
release:
|
release:
|
||||||
name: Deploy
|
name: Deploy
|
||||||
needs: [ test, test-jdk8-macos, test-oracle, javadoc ]
|
needs: [ test, test-jdk8, test-oracle ]
|
||||||
if: github.ref == 'refs/heads/master' # only perform on latest master
|
if: github.ref == 'refs/heads/master' # only perform on latest master
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
- name: Set up Maven Central
|
- name: Set up Maven Central
|
||||||
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
|
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
|
||||||
with: # running setup-java again overwrites the settings.xml
|
with: # running setup-java again overwrites the settings.xml
|
||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
java-version: '8'
|
java-version: '8'
|
||||||
java-package: jdk
|
java-package: jdk
|
||||||
server-id: central # Value of the distributionManagement/repository/id field of the pom.xml
|
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-username: MAVEN_CENTRAL_USERNAME # env variable for username in deploy (1)
|
||||||
server-password: MAVEN_CENTRAL_PASSWORD # env variable for token in deploy (2)
|
server-password: MAVEN_CENTRAL_PASSWORD # env variable for token in deploy (2)
|
||||||
- name: Get Project Version
|
- name: Get Project Version
|
||||||
@@ -137,7 +121,7 @@ jobs:
|
|||||||
if: ${{ endsWith(env.PROJECT_VERSION, '-SNAPSHOT') }}
|
if: ${{ endsWith(env.PROJECT_VERSION, '-SNAPSHOT') }}
|
||||||
run: mvn --batch-mode --no-transfer-progress deploy -P release -DskipTests -Dgpg.signer=bc
|
run: mvn --batch-mode --no-transfer-progress deploy -P release -DskipTests -Dgpg.signer=bc
|
||||||
env:
|
env:
|
||||||
MAVEN_CENTRAL_USERNAME: ${{ secrets.CENTRAL_USERNAME }} # must be the same env variable name as (1)
|
MAVEN_CENTRAL_USERNAME: ${{ secrets.SONATYPE_USERNAME }} # must be the same env variable name as (1)
|
||||||
MAVEN_CENTRAL_PASSWORD: ${{ secrets.CENTRAL_PASSWORD }} # must be the same env variable name as (2)
|
MAVEN_CENTRAL_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} # must be the same env variable name as (2)
|
||||||
MAVEN_GPG_KEY: ${{ secrets.GPG_KEY }} # Value of the GPG private key to import
|
MAVEN_GPG_KEY: ${{ secrets.GPG_KEY }} # Value of the GPG private key to import
|
||||||
MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
||||||
|
|||||||
@@ -33,11 +33,11 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4
|
uses: github/codeql-action/init@fca7ace96b7d713c7035871441bd52efbe39e27e # v3.28.19
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
@@ -51,7 +51,7 @@ jobs:
|
|||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
|
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4
|
uses: github/codeql-action/autobuild@fca7ace96b7d713c7035871441bd52efbe39e27e # v3.28.19
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||||
@@ -64,6 +64,6 @@ jobs:
|
|||||||
# ./location_of_script_within_repo/buildscript.sh
|
# ./location_of_script_within_repo/buildscript.sh
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4
|
uses: github/codeql-action/analyze@fca7ace96b7d713c7035871441bd52efbe39e27e # v3.28.19
|
||||||
with:
|
with:
|
||||||
category: "/language:${{matrix.language}}"
|
category: "/language:${{matrix.language}}"
|
||||||
|
|||||||
@@ -26,12 +26,12 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: "Checkout code"
|
- name: "Checkout code"
|
||||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: "Run analysis"
|
- name: "Run analysis"
|
||||||
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
|
uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2
|
||||||
with:
|
with:
|
||||||
results_file: results.sarif
|
results_file: results.sarif
|
||||||
results_format: sarif
|
results_format: sarif
|
||||||
@@ -49,7 +49,7 @@ jobs:
|
|||||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||||
# format to the repository Actions tab.
|
# format to the repository Actions tab.
|
||||||
- name: "Upload artifact"
|
- name: "Upload artifact"
|
||||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||||
with:
|
with:
|
||||||
name: SARIF file
|
name: SARIF file
|
||||||
path: results.sarif
|
path: results.sarif
|
||||||
@@ -57,6 +57,6 @@ jobs:
|
|||||||
|
|
||||||
# Upload the results to GitHub's code scanning dashboard.
|
# Upload the results to GitHub's code scanning dashboard.
|
||||||
- name: "Upload to code-scanning"
|
- name: "Upload to code-scanning"
|
||||||
uses: github/codeql-action/upload-sarif@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4
|
uses: github/codeql-action/upload-sarif@fca7ace96b7d713c7035871441bd52efbe39e27e # v3.28.19
|
||||||
with:
|
with:
|
||||||
sarif_file: results.sarif
|
sarif_file: results.sarif
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
[](https://www.bestpractices.dev/projects/7900)
|
[](https://www.bestpractices.dev/projects/7900)
|
||||||
|
|
||||||
[](https://search.maven.org/search?q=g:com.twelvemonkeys.imageio)
|
[](https://search.maven.org/search?q=g:com.twelvemonkeys.imageio)
|
||||||
[](https://central.sonatype.com/repository/maven-snapshots/com/twelvemonkeys/imageio/imageio/maven-metadata.xml)
|
[](https://oss.sonatype.org/content/repositories/snapshots/com/twelvemonkeys/)
|
||||||
[](https://stackoverflow.com/questions/tagged/twelvemonkeys)
|
[](https://stackoverflow.com/questions/tagged/twelvemonkeys)
|
||||||
[](https://paypal.me/haraldk76/100)
|
[](https://paypal.me/haraldk76/100)
|
||||||
|
|
||||||
@@ -316,12 +316,12 @@ To depend on the JPEG and TIFF plugin using Maven, add the following to your POM
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio-jpeg</artifactId>
|
<artifactId>imageio-jpeg</artifactId>
|
||||||
<version>3.13.1</version>
|
<version>3.12.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio-tiff</artifactId>
|
<artifactId>imageio-tiff</artifactId>
|
||||||
<version>3.13.1</version>
|
<version>3.12.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
@@ -331,7 +331,7 @@ To depend on the JPEG and TIFF plugin using Maven, add the following to your POM
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.servlet</groupId>
|
<groupId>com.twelvemonkeys.servlet</groupId>
|
||||||
<artifactId>servlet</artifactId>
|
<artifactId>servlet</artifactId>
|
||||||
<version>3.13.1</version>
|
<version>3.12.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
@@ -340,7 +340,7 @@ To depend on the JPEG and TIFF plugin using Maven, add the following to your POM
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.twelvemonkeys.servlet</groupId>
|
<groupId>com.twelvemonkeys.servlet</groupId>
|
||||||
<artifactId>servlet</artifactId>
|
<artifactId>servlet</artifactId>
|
||||||
<version>3.13.1</version>
|
<version>3.12.0</version>
|
||||||
<classifier>jakarta</classifier>
|
<classifier>jakarta</classifier>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
@@ -350,13 +350,13 @@ To depend on the JPEG and TIFF plugin using Maven, add the following to your POM
|
|||||||
|
|
||||||
To depend on the JPEG and TIFF plugin in your IDE or program, add all of the following JARs to your class path:
|
To depend on the JPEG and TIFF plugin in your IDE or program, add all of the following JARs to your class path:
|
||||||
|
|
||||||
twelvemonkeys-common-lang-3.13.1.jar
|
twelvemonkeys-common-lang-3.12.0.jar
|
||||||
twelvemonkeys-common-io-3.13.1.jar
|
twelvemonkeys-common-io-3.12.0.jar
|
||||||
twelvemonkeys-common-image-3.13.1.jar
|
twelvemonkeys-common-image-3.12.0.jar
|
||||||
twelvemonkeys-imageio-core-3.13.1.jar
|
twelvemonkeys-imageio-core-3.12.0.jar
|
||||||
twelvemonkeys-imageio-metadata-3.13.1.jar
|
twelvemonkeys-imageio-metadata-3.12.0.jar
|
||||||
twelvemonkeys-imageio-jpeg-3.13.1.jar
|
twelvemonkeys-imageio-jpeg-3.12.0.jar
|
||||||
twelvemonkeys-imageio-tiff-3.13.1.jar
|
twelvemonkeys-imageio-tiff-3.12.0.jar
|
||||||
|
|
||||||
#### Deploying the plugins in a web app
|
#### Deploying the plugins in a web app
|
||||||
|
|
||||||
@@ -432,46 +432,46 @@ Other "fat" JAR bundlers will probably have similar mechanisms to merge entries
|
|||||||
|
|
||||||
### Links to prebuilt binaries
|
### Links to prebuilt binaries
|
||||||
|
|
||||||
##### Latest version (3.13.1)
|
##### Latest version (3.12.0)
|
||||||
|
|
||||||
The latest version that will run on Java 7 is 3.9.4. Later versions will require Java 8 or later.
|
The latest version that will run on Java 7 is 3.9.4. Later versions will require Java 8 or later.
|
||||||
|
|
||||||
Common dependencies
|
Common dependencies
|
||||||
* [common-lang-3.13.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-lang/3.13.1/common-lang-3.13.1.jar)
|
* [common-lang-3.12.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-lang/3.12.0/common-lang-3.12.0.jar)
|
||||||
* [common-io-3.13.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-io/3.13.1/common-io-3.13.1.jar)
|
* [common-io-3.12.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-io/3.12.0/common-io-3.12.0.jar)
|
||||||
* [common-image-3.13.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-image/3.13.1/common-image-3.13.1.jar)
|
* [common-image-3.12.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-image/3.12.0/common-image-3.12.0.jar)
|
||||||
|
|
||||||
ImageIO dependencies
|
ImageIO dependencies
|
||||||
* [imageio-core-3.13.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-core/3.13.1/imageio-core-3.13.1.jar)
|
* [imageio-core-3.12.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-core/3.12.0/imageio-core-3.12.0.jar)
|
||||||
* [imageio-metadata-3.13.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-metadata/3.13.1/imageio-metadata-3.13.1.jar)
|
* [imageio-metadata-3.12.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-metadata/3.12.0/imageio-metadata-3.12.0.jar)
|
||||||
|
|
||||||
ImageIO plugins
|
ImageIO plugins
|
||||||
* [imageio-bmp-3.13.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-bmp/3.13.1/imageio-bmp-3.13.1.jar)
|
* [imageio-bmp-3.12.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-bmp/3.12.0/imageio-bmp-3.12.0.jar)
|
||||||
* [imageio-dds-3.13.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-dds/3.13.1/imageio-dds-3.13.1.jar)
|
* [imageio-dds-3.12.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-dds/3.12.0/imageio-dds-3.12.0.jar)
|
||||||
* [imageio-hdr-3.13.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-hdr/3.13.1/imageio-hdr-3.13.1.jar)
|
* [imageio-hdr-3.12.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-hdr/3.12.0/imageio-hdr-3.12.0.jar)
|
||||||
* [imageio-icns-3.13.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-icns/3.13.1/imageio-icns-3.13.1.jar)
|
* [imageio-icns-3.12.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-icns/3.12.0/imageio-icns-3.12.0.jar)
|
||||||
* [imageio-iff-3.13.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-iff/3.13.1/imageio-iff-3.13.1.jar)
|
* [imageio-iff-3.12.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-iff/3.12.0/imageio-iff-3.12.0.jar)
|
||||||
* [imageio-jpeg-3.13.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jpeg/3.13.1/imageio-jpeg-3.13.1.jar)
|
* [imageio-jpeg-3.12.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jpeg/3.12.0/imageio-jpeg-3.12.0.jar)
|
||||||
* [imageio-pcx-3.13.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pcx/3.13.1/imageio-pcx-3.13.1.jar)
|
* [imageio-pcx-3.12.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pcx/3.12.0/imageio-pcx-3.12.0.jar)
|
||||||
* [imageio-pict-3.13.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pict/3.13.1/imageio-pict-3.13.1.jar)
|
* [imageio-pict-3.12.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pict/3.12.0/imageio-pict-3.12.0.jar)
|
||||||
* [imageio-pnm-3.13.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pnm/3.13.1/imageio-pnm-3.13.1.jar)
|
* [imageio-pnm-3.12.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pnm/3.12.0/imageio-pnm-3.12.0.jar)
|
||||||
* [imageio-psd-3.13.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-psd/3.13.1/imageio-psd-3.13.1.jar)
|
* [imageio-psd-3.12.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-psd/3.12.0/imageio-psd-3.12.0.jar)
|
||||||
* [imageio-sgi-3.13.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-sgi/3.13.1/imageio-sgi-3.13.1.jar)
|
* [imageio-sgi-3.12.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-sgi/3.12.0/imageio-sgi-3.12.0.jar)
|
||||||
* [imageio-tga-3.13.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tga/3.13.1/imageio-tga-3.13.1.jar)
|
* [imageio-tga-3.12.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tga/3.12.0/imageio-tga-3.12.0.jar)
|
||||||
* [imageio-thumbsdb-3.13.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-thumbsdb/3.13.1/imageio-thumbsdb-3.13.1.jar)
|
* [imageio-thumbsdb-3.12.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-thumbsdb/3.12.0/imageio-thumbsdb-3.12.0.jar)
|
||||||
* [imageio-tiff-3.13.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tiff/3.13.1/imageio-tiff-3.13.1.jar)
|
* [imageio-tiff-3.12.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tiff/3.12.0/imageio-tiff-3.12.0.jar)
|
||||||
* [imageio-webp-3.13.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-webp/3.13.1/imageio-webp-3.13.1.jar)
|
* [imageio-webp-3.12.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-webp/3.12.0/imageio-webp-3.12.0.jar)
|
||||||
* [imageio-xwd-3.13.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-xwd/3.13.1/imageio-xwd-3.13.1.jar)
|
* [imageio-xwd-3.12.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-xwd/3.12.0/imageio-xwd-3.12.0.jar)
|
||||||
|
|
||||||
ImageIO plugins requiring 3rd party libs
|
ImageIO plugins requiring 3rd party libs
|
||||||
* [imageio-batik-3.13.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-batik/3.13.1/imageio-batik-3.13.1.jar)
|
* [imageio-batik-3.12.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-batik/3.12.0/imageio-batik-3.12.0.jar)
|
||||||
|
|
||||||
Photoshop Path support for ImageIO
|
Photoshop Path support for ImageIO
|
||||||
* [imageio-clippath-3.13.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-clippath/3.13.1/imageio-clippath-3.13.1.jar)
|
* [imageio-clippath-3.12.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-clippath/3.12.0/imageio-clippath-3.12.0.jar)
|
||||||
|
|
||||||
Servlet support
|
Servlet support
|
||||||
* [servlet-3.13.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/servlet/servlet/3.13.1/servlet-3.13.1.jar) for legacy Java EE (javax.servlet)
|
* [servlet-3.12.0.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/servlet/servlet/3.12.0/servlet-3.12.0.jar) for legacy Java EE (javax.servlet)
|
||||||
* [servlet-3.13.1-jakarta.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/servlet/servlet/3.13.1/servlet-3.13.1-jakrta.jar) for Jakarta EE (jakarta.servlet)
|
* [servlet-3.12.0-jakarta.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/servlet/servlet/3.12.0/servlet-3.12.0-jakrta.jar) for Jakarta EE (jakarta.servlet)
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -5,13 +5,13 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys</groupId>
|
<groupId>com.twelvemonkeys</groupId>
|
||||||
<artifactId>twelvemonkeys</artifactId>
|
<artifactId>twelvemonkeys</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<groupId>com.twelvemonkeys.bom</groupId>
|
<groupId>com.twelvemonkeys.bom</groupId>
|
||||||
<artifactId>bom</artifactId>
|
<artifactId>bom</artifactId>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<name>TwelveMonkeys » BOM</name>
|
<name>TwelveMonkeys :: BOM</name>
|
||||||
<description>
|
<description>
|
||||||
TwelveMonkeys "Bill of Materials" (BOM).
|
TwelveMonkeys "Bill of Materials" (BOM).
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
@@ -4,11 +4,11 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.common</groupId>
|
<groupId>com.twelvemonkeys.common</groupId>
|
||||||
<artifactId>common</artifactId>
|
<artifactId>common</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>common-image</artifactId>
|
<artifactId>common-image</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<name>TwelveMonkeys » Common » Image</name>
|
<name>TwelveMonkeys :: Common :: Image</name>
|
||||||
<description>
|
<description>
|
||||||
TwelveMonkeys Common image support classes.
|
TwelveMonkeys Common image support classes.
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
@@ -47,10 +47,10 @@ import java.util.Random;
|
|||||||
* |3|5|1|
|
* |3|5|1|
|
||||||
* - - -->
|
* - - -->
|
||||||
* </p>
|
* </p>
|
||||||
* <table border="1">
|
* <table border="1" cellpadding="4" cellspacing="0">
|
||||||
* <caption>Floyd-Steinberg error-diffusion weights</caption>
|
* <caption>Floyd-Steinberg error-diffusion weights</caption>
|
||||||
* <tr><td style="background:#000000"> </td><td class="TableHeadingColor"
|
* <tr><td bgcolor="#000000"> </td><td class="TableHeadingColor"
|
||||||
* style="text-align:center">x</td><td>7/16</td></tr>
|
* align="center">x</td><td>7/16</td></tr>
|
||||||
* <tr><td>3/16</td><td>5/16</td><td>1/16</td></tr>
|
* <tr><td>3/16</td><td>5/16</td><td>1/16</td></tr>
|
||||||
* </table>
|
* </table>
|
||||||
* <p>
|
* <p>
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ public final class ImageUtil {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The sharpen kernel. Uses the following 3 by 3 matrix:
|
* The sharpen kernel. Uses the following 3 by 3 matrix:
|
||||||
* <table border="1">
|
* <table border="1" cellspacing="0">
|
||||||
* <caption>Sharpen Kernel Matrix</caption>
|
* <caption>Sharpen Kernel Matrix</caption>
|
||||||
* <tr><td>0.0</td><td>-0.3</td><td>0.0</td></tr>
|
* <tr><td>0.0</td><td>-0.3</td><td>0.0</td></tr>
|
||||||
* <tr><td>-0.3</td><td>2.2</td><td>-0.3</td></tr>
|
* <tr><td>-0.3</td><td>2.2</td><td>-0.3</td></tr>
|
||||||
@@ -1078,7 +1078,7 @@ public final class ImageUtil {
|
|||||||
/**
|
/**
|
||||||
* Sharpens an image using a convolution matrix.
|
* Sharpens an image using a convolution matrix.
|
||||||
* The sharpen kernel used, is defined by the following 3 by 3 matrix:
|
* The sharpen kernel used, is defined by the following 3 by 3 matrix:
|
||||||
* <table border="1">
|
* <table border="1" cellspacing="0">
|
||||||
* <caption>Sharpen Kernel Matrix</caption>
|
* <caption>Sharpen Kernel Matrix</caption>
|
||||||
* <tr><td>0.0</td><td>-0.3</td><td>0.0</td></tr>
|
* <tr><td>0.0</td><td>-0.3</td><td>0.0</td></tr>
|
||||||
* <tr><td>-0.3</td><td>2.2</td><td>-0.3</td></tr>
|
* <tr><td>-0.3</td><td>2.2</td><td>-0.3</td></tr>
|
||||||
@@ -1100,7 +1100,7 @@ public final class ImageUtil {
|
|||||||
/**
|
/**
|
||||||
* Sharpens an image using a convolution matrix.
|
* Sharpens an image using a convolution matrix.
|
||||||
* The sharpen kernel used, is defined by the following 3 by 3 matrix:
|
* The sharpen kernel used, is defined by the following 3 by 3 matrix:
|
||||||
* <table border="1">
|
* <table border="1" cellspacing="0">
|
||||||
* <caption>Sharpen Kernel Matrix</caption>
|
* <caption>Sharpen Kernel Matrix</caption>
|
||||||
* <tr><td>0.0</td><td>-{@code pAmount}</td><td>0.0</td></tr>
|
* <tr><td>0.0</td><td>-{@code pAmount}</td><td>0.0</td></tr>
|
||||||
* <tr><td>-{@code pAmount}</td>
|
* <tr><td>-{@code pAmount}</td>
|
||||||
|
|||||||
@@ -4,11 +4,11 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.common</groupId>
|
<groupId>com.twelvemonkeys.common</groupId>
|
||||||
<artifactId>common</artifactId>
|
<artifactId>common</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>common-io</artifactId>
|
<artifactId>common-io</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<name>TwelveMonkeys » Common » IO</name>
|
<name>TwelveMonkeys :: Common :: IO</name>
|
||||||
<description>
|
<description>
|
||||||
TwelveMonkeys Common I/O support classes.
|
TwelveMonkeys Common I/O support classes.
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
@@ -4,11 +4,11 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.common</groupId>
|
<groupId>com.twelvemonkeys.common</groupId>
|
||||||
<artifactId>common</artifactId>
|
<artifactId>common</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>common-lang</artifactId>
|
<artifactId>common-lang</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<name>TwelveMonkeys » Common » Language support</name>
|
<name>TwelveMonkeys :: Common :: Language support</name>
|
||||||
<description>
|
<description>
|
||||||
TwelveMonkeys Common language support classes.
|
TwelveMonkeys Common language support classes.
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
@@ -1765,11 +1765,12 @@ public final class StringUtil {
|
|||||||
* expression.
|
* expression.
|
||||||
* <p>
|
* <p>
|
||||||
* An invocation of this method of the form
|
* An invocation of this method of the form
|
||||||
* {@code matches(str, regex)} yields exactly the
|
* <tt>matches(<i>str</i>, <i>regex</i>)</tt> yields exactly the
|
||||||
* same result as the expression
|
* same result as the expression
|
||||||
* </p>
|
* </p>
|
||||||
* <blockquote>{@link Pattern}.
|
* <blockquote><tt> {@link Pattern}.
|
||||||
* {@link Pattern#matches(String, CharSequence) matches(regex, str)}</blockquote>
|
* {@link Pattern#matches(String, CharSequence) matches}
|
||||||
|
* (<i>regex</i>, <i>str</i>)</tt></blockquote>
|
||||||
*
|
*
|
||||||
* @param pString the string
|
* @param pString the string
|
||||||
* @param pRegex the regular expression to which this string is to be matched
|
* @param pRegex the regular expression to which this string is to be matched
|
||||||
@@ -1788,14 +1789,16 @@ public final class StringUtil {
|
|||||||
* regular expression with the given pReplacement.
|
* regular expression with the given pReplacement.
|
||||||
* <p>
|
* <p>
|
||||||
* An invocation of this method of the form
|
* An invocation of this method of the form
|
||||||
* {@code replaceFirst(str, regex, repl)}
|
* <tt>
|
||||||
|
* replaceFirst(<i>str</i>, <i>regex</i>, <i>repl</i>)
|
||||||
|
* </tt>
|
||||||
* yields exactly the same result as the expression:
|
* yields exactly the same result as the expression:
|
||||||
* </p>
|
* </p>
|
||||||
* <blockquote>
|
* <blockquote><tt>
|
||||||
* {@link Pattern#compile(String) Pattern.compile(regex)}
|
* {@link Pattern}.{@link Pattern#compile(String) compile}(<i>regex</i>).
|
||||||
* {@link Pattern#matcher .matcher(str)}
|
* {@link Pattern#matcher matcher}(<i>str</i>).
|
||||||
* {@link java.util.regex.Matcher#replaceFirst .replaceFirst(repl)}
|
* {@link java.util.regex.Matcher#replaceFirst replaceFirst}(<i>repl</i>)
|
||||||
* </blockquote>
|
* </tt></blockquote>
|
||||||
*
|
*
|
||||||
* @param pString the string
|
* @param pString the string
|
||||||
* @param pRegex the regular expression to which this string is to be matched
|
* @param pRegex the regular expression to which this string is to be matched
|
||||||
@@ -1814,14 +1817,14 @@ public final class StringUtil {
|
|||||||
* regular expression with the given pReplacement.
|
* regular expression with the given pReplacement.
|
||||||
* <p>
|
* <p>
|
||||||
* An invocation of this method of the form
|
* An invocation of this method of the form
|
||||||
* {@code replaceAll(str, pRegex, repl)}
|
* <tt>replaceAll(<i>str</i>, <i>pRegex</i>, <i>repl</i>)</tt>
|
||||||
* yields exactly the same result as the expression
|
* yields exactly the same result as the expression
|
||||||
* </p>
|
* </p>
|
||||||
* <blockquote>
|
* <blockquote><tt>
|
||||||
* {@link Pattern#compile(String) Pattern.compile(pRegex)}
|
* {@link Pattern}.{@link Pattern#compile(String) compile}(<i>pRegex</i>).
|
||||||
* {@link Pattern#matcher .matcher(str)}
|
* {@link Pattern#matcher matcher}(<i>str</i>{@code ).
|
||||||
* {@link java.util.regex.Matcher#replaceAll .replaceAll(repl)}
|
* {@link java.util.regex.Matcher#replaceAll replaceAll}(}<i>repl</i>{@code )}
|
||||||
* </blockquote>
|
* </tt></blockquote>
|
||||||
*
|
*
|
||||||
* @param pString the string
|
* @param pString the string
|
||||||
* @param pRegex the regular expression to which this string is to be matched
|
* @param pRegex the regular expression to which this string is to be matched
|
||||||
@@ -1859,12 +1862,12 @@ public final class StringUtil {
|
|||||||
* </p>
|
* </p>
|
||||||
* <p>
|
* <p>
|
||||||
* An invocation of this method of the form
|
* An invocation of this method of the form
|
||||||
* {@code split(str, regex, n)}
|
* <tt>split(<i>str</i>, <i>regex</i>, <i>n</i>)</tt>
|
||||||
* yields the same result as the expression:
|
* yields the same result as the expression:
|
||||||
* </p>
|
* </p>
|
||||||
* <blockquote>{@link Pattern}.
|
* <blockquote>{@link Pattern}.
|
||||||
* {@link Pattern#compile(String) compile(regex)}.
|
* {@link Pattern#compile(String) compile}<tt>(<i>regex</i>).
|
||||||
* {@link Pattern#split(CharSequence,int) split(str, n)}
|
* {@link Pattern#split(CharSequence,int) split}(<i>str</i>, <i>n</i>)</tt>
|
||||||
* </blockquote>
|
* </blockquote>
|
||||||
*
|
*
|
||||||
* @param pString the string
|
* @param pString the string
|
||||||
|
|||||||
@@ -284,6 +284,20 @@ abstract class AbstractDecoratedMap<K, V> extends AbstractMap<K, V> implements M
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// NOTE: Extra cautions is taken, to only remove the entry if it
|
||||||
|
// equals the entry in the map
|
||||||
|
Object key = ((Entry) o).getKey();
|
||||||
|
Entry entry = (Entry) entries.get(key);
|
||||||
|
|
||||||
|
// Same entry?
|
||||||
|
if (entry != null && entry.equals(o)) {
|
||||||
|
return AbstractWrappedMap.this.remove(key) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
*/
|
||||||
|
|
||||||
//noinspection unchecked
|
//noinspection unchecked
|
||||||
return AbstractDecoratedMap.this.removeEntry((Entry) o) != null;
|
return AbstractDecoratedMap.this.removeEntry((Entry) o) != null;
|
||||||
}
|
}
|
||||||
@@ -308,7 +322,7 @@ abstract class AbstractDecoratedMap<K, V> extends AbstractMap<K, V> implements M
|
|||||||
return containsKey(o);
|
return containsKey(o);
|
||||||
}
|
}
|
||||||
public boolean remove(Object o) {
|
public boolean remove(Object o) {
|
||||||
return AbstractDecoratedMap.this.removeEntry(getEntry((K) o)) != null;
|
return AbstractDecoratedMap.this.remove(o) != null;
|
||||||
}
|
}
|
||||||
public void clear() {
|
public void clear() {
|
||||||
AbstractDecoratedMap.this.clear();
|
AbstractDecoratedMap.this.clear();
|
||||||
|
|||||||
@@ -137,43 +137,43 @@ public final class BeanMap extends AbstractMap<String, Object> implements Serial
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class BeanIterator implements Iterator<Entry<String, Object>> {
|
private class BeanIterator implements Iterator<Entry<String, Object>> {
|
||||||
private final Iterator<PropertyDescriptor> iterator;
|
private final Iterator<PropertyDescriptor> mIterator;
|
||||||
|
|
||||||
public BeanIterator(final Iterator<PropertyDescriptor> pIterator) {
|
public BeanIterator(final Iterator<PropertyDescriptor> pIterator) {
|
||||||
iterator = pIterator;
|
mIterator = pIterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
return iterator.hasNext();
|
return mIterator.hasNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
public BeanEntry next() {
|
public BeanEntry next() {
|
||||||
return new BeanEntry(iterator.next());
|
return new BeanEntry(mIterator.next());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove() {
|
public void remove() {
|
||||||
iterator.remove();
|
mIterator.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BeanEntry implements Entry<String, Object> {
|
private class BeanEntry implements Entry<String, Object> {
|
||||||
private final PropertyDescriptor descriptor;
|
private final PropertyDescriptor mDescriptor;
|
||||||
|
|
||||||
public BeanEntry(final PropertyDescriptor pDescriptor) {
|
public BeanEntry(final PropertyDescriptor pDescriptor) {
|
||||||
this.descriptor = pDescriptor;
|
this.mDescriptor = pDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getKey() {
|
public String getKey() {
|
||||||
return descriptor.getName();
|
return mDescriptor.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getValue() {
|
public Object getValue() {
|
||||||
return unwrap(new Wrapped() {
|
return unwrap(new Wrapped() {
|
||||||
public Object run() throws IllegalAccessException, InvocationTargetException {
|
public Object run() throws IllegalAccessException, InvocationTargetException {
|
||||||
final Method method = descriptor.getReadMethod();
|
final Method method = mDescriptor.getReadMethod();
|
||||||
// A write-only bean.
|
// A write-only bean.
|
||||||
if (method == null) {
|
if (method == null) {
|
||||||
throw new UnsupportedOperationException("No getter: " + descriptor.getName());
|
throw new UnsupportedOperationException("No getter: " + mDescriptor.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
return method.invoke(bean);
|
return method.invoke(bean);
|
||||||
@@ -184,10 +184,10 @@ public final class BeanMap extends AbstractMap<String, Object> implements Serial
|
|||||||
public Object setValue(final Object pValue) {
|
public Object setValue(final Object pValue) {
|
||||||
return unwrap(new Wrapped() {
|
return unwrap(new Wrapped() {
|
||||||
public Object run() throws IllegalAccessException, InvocationTargetException {
|
public Object run() throws IllegalAccessException, InvocationTargetException {
|
||||||
final Method method = descriptor.getWriteMethod();
|
final Method method = mDescriptor.getWriteMethod();
|
||||||
// A read-only bean.
|
// A read-only bean.
|
||||||
if (method == null) {
|
if (method == null) {
|
||||||
throw new UnsupportedOperationException("No write method for property: " + descriptor.getName());
|
throw new UnsupportedOperationException("No write method for property: " + mDescriptor.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
final Object old = getValue();
|
final Object old = getValue();
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ public abstract class ObjectAbstractTest {
|
|||||||
// TODO: What more can we test?
|
// TODO: What more can we test?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: assert that either BOTH or NONE of equals/hashcode is overridden
|
||||||
@Test
|
@Test
|
||||||
public void testEqualsHashCode(){
|
public void testEqualsHashCode(){
|
||||||
Object obj = makeObject();
|
Object obj = makeObject();
|
||||||
@@ -327,4 +328,5 @@ public abstract class ObjectAbstractTest {
|
|||||||
return new Cloneable() {};
|
return new Cloneable() {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,8 +30,6 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.util;
|
package com.twelvemonkeys.util;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Nested;
|
|
||||||
|
|
||||||
import java.beans.IntrospectionException;
|
import java.beans.IntrospectionException;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -174,16 +172,4 @@ public class BeanMapTest extends MapAbstractTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static class NullBean implements Serializable { }
|
static class NullBean implements Serializable { }
|
||||||
|
|
||||||
@Nested
|
|
||||||
public class TestBeanMapEntrySet extends TestMapEntrySet {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nested
|
|
||||||
public class TestBeanMapKeySet extends TestMapKeySet {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nested
|
|
||||||
public class TestBeanMapValues extends TestMapValues {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-15
@@ -436,24 +436,24 @@ public abstract class CollectionAbstractTest extends ObjectAbstractTest {
|
|||||||
*/
|
*/
|
||||||
public Object[] getFullNonNullElements() {
|
public Object[] getFullNonNullElements() {
|
||||||
return new Object[] {
|
return new Object[] {
|
||||||
"",
|
new String(""),
|
||||||
"One",
|
new String("One"),
|
||||||
2,
|
new Integer(2),
|
||||||
"Three",
|
"Three",
|
||||||
4,
|
new Integer(4),
|
||||||
"One",
|
"One",
|
||||||
5.0,
|
new Double(5),
|
||||||
6F,
|
new Float(6),
|
||||||
"Seven",
|
"Seven",
|
||||||
"Eight",
|
"Eight",
|
||||||
"Nine",
|
new String("Nine"),
|
||||||
10,
|
new Integer(10),
|
||||||
(short) 11,
|
new Short((short)11),
|
||||||
12L,
|
new Long(12),
|
||||||
"Thirteen",
|
"Thirteen",
|
||||||
"14",
|
"14",
|
||||||
"15",
|
"15",
|
||||||
(byte) 16
|
new Byte((byte)16)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1149,7 +1149,7 @@ public abstract class CollectionAbstractTest extends ObjectAbstractTest {
|
|||||||
public void testUnsupportedRemove() {
|
public void testUnsupportedRemove() {
|
||||||
if (isRemoveSupported()) return;
|
if (isRemoveSupported()) return;
|
||||||
|
|
||||||
resetFull();
|
resetEmpty();
|
||||||
try {
|
try {
|
||||||
collection.clear();
|
collection.clear();
|
||||||
fail("clear should raise UnsupportedOperationException");
|
fail("clear should raise UnsupportedOperationException");
|
||||||
@@ -1159,7 +1159,7 @@ public abstract class CollectionAbstractTest extends ObjectAbstractTest {
|
|||||||
verifyAll();
|
verifyAll();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
collection.remove(getFullElements()[0]);
|
collection.remove(null);
|
||||||
fail("remove should raise UnsupportedOperationException");
|
fail("remove should raise UnsupportedOperationException");
|
||||||
} catch (UnsupportedOperationException e) {
|
} catch (UnsupportedOperationException e) {
|
||||||
// expected
|
// expected
|
||||||
@@ -1167,7 +1167,7 @@ public abstract class CollectionAbstractTest extends ObjectAbstractTest {
|
|||||||
verifyAll();
|
verifyAll();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
collection.removeAll(Arrays.asList(getFullElements()));
|
collection.removeAll(null);
|
||||||
fail("removeAll should raise UnsupportedOperationException");
|
fail("removeAll should raise UnsupportedOperationException");
|
||||||
} catch (UnsupportedOperationException e) {
|
} catch (UnsupportedOperationException e) {
|
||||||
// expected
|
// expected
|
||||||
@@ -1175,7 +1175,7 @@ public abstract class CollectionAbstractTest extends ObjectAbstractTest {
|
|||||||
verifyAll();
|
verifyAll();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
collection.retainAll(Collections.emptySet());
|
collection.retainAll(null);
|
||||||
fail("removeAll should raise UnsupportedOperationException");
|
fail("removeAll should raise UnsupportedOperationException");
|
||||||
} catch (UnsupportedOperationException e) {
|
} catch (UnsupportedOperationException e) {
|
||||||
// expected
|
// expected
|
||||||
@@ -1192,6 +1192,7 @@ public abstract class CollectionAbstractTest extends ObjectAbstractTest {
|
|||||||
// expected
|
// expected
|
||||||
}
|
}
|
||||||
verifyAll();
|
verifyAll();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -212,17 +212,5 @@ public class LRUMapTest extends LinkedMapTest {
|
|||||||
list.add(pEntry.getKey());
|
list.add(pEntry.getKey());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nested
|
|
||||||
public class TestLRUMapEntrySet extends TestMapEntrySet {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nested
|
|
||||||
public class TestLRUMapKeySet extends TestMapKeySet {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nested
|
|
||||||
public class TestLRUMapValues extends TestMapValues {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -201,16 +201,4 @@ public class LinkedMapTest extends MapAbstractTest {
|
|||||||
public void tearDown() throws Exception {
|
public void tearDown() throws Exception {
|
||||||
labRat = null;
|
labRat = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nested
|
|
||||||
public class TestLinkedMapEntrySet extends TestMapEntrySet {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nested
|
|
||||||
public class TestLinkedMapKeySet extends TestMapKeySet {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nested
|
|
||||||
public class TestLinkedMapValues extends TestMapValues {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1255,7 +1255,7 @@ public abstract class MapAbstractTest extends ObjectAbstractTest {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
protected abstract class TestMapEntrySet extends SetAbstractTest {
|
public class TestMapEntrySet extends SetAbstractTest {
|
||||||
|
|
||||||
// Have to implement manually; entrySet doesn't support addAll
|
// Have to implement manually; entrySet doesn't support addAll
|
||||||
public Object[] getFullElements() {
|
public Object[] getFullElements() {
|
||||||
@@ -1429,7 +1429,7 @@ public abstract class MapAbstractTest extends ObjectAbstractTest {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
protected abstract class TestMapKeySet extends SetAbstractTest {
|
public class TestMapKeySet extends SetAbstractTest {
|
||||||
public Object[] getFullElements() {
|
public Object[] getFullElements() {
|
||||||
return getSampleKeys();
|
return getSampleKeys();
|
||||||
}
|
}
|
||||||
@@ -1495,7 +1495,7 @@ public abstract class MapAbstractTest extends ObjectAbstractTest {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
protected abstract class TestMapValues extends CollectionAbstractTest {
|
public class TestMapValues extends CollectionAbstractTest {
|
||||||
public Object[] getFullElements() {
|
public Object[] getFullElements() {
|
||||||
return getSampleValues();
|
return getSampleValues();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -668,17 +668,5 @@ public class TimeoutMapTest extends MapAbstractTest {
|
|||||||
assertFalse(timeoutMap.containsKey("xyz"));
|
assertFalse(timeoutMap.containsKey("xyz"));
|
||||||
assertNull(timeoutMap.get("xyz"));
|
assertNull(timeoutMap.get("xyz"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nested
|
|
||||||
public class TestTimeoutMapEntrySet extends TestMapEntrySet {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nested
|
|
||||||
public class TestTimeoutMapKeySet extends TestMapKeySet {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nested
|
|
||||||
public class TestTimeoutMapValues extends TestMapValues {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -4,12 +4,12 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys</groupId>
|
<groupId>com.twelvemonkeys</groupId>
|
||||||
<artifactId>twelvemonkeys</artifactId>
|
<artifactId>twelvemonkeys</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<groupId>com.twelvemonkeys.common</groupId>
|
<groupId>com.twelvemonkeys.common</groupId>
|
||||||
<artifactId>common</artifactId>
|
<artifactId>common</artifactId>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<name>TwelveMonkeys » Common</name>
|
<name>TwelveMonkeys :: Common</name>
|
||||||
<description>
|
<description>
|
||||||
The TwelveMonkeys Common library. Contains common utility classes.
|
The TwelveMonkeys Common library. Contains common utility classes.
|
||||||
</description>
|
</description>
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<junit.jupiter.version>5.14.4</junit.jupiter.version>
|
<junit.jupiter.version>5.13.0</junit.jupiter.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencyManagement>
|
<dependencyManagement>
|
||||||
|
|||||||
+3
-3
@@ -4,17 +4,17 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys</groupId>
|
<groupId>com.twelvemonkeys</groupId>
|
||||||
<artifactId>twelvemonkeys</artifactId>
|
<artifactId>twelvemonkeys</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<groupId>com.twelvemonkeys.contrib</groupId>
|
<groupId>com.twelvemonkeys.contrib</groupId>
|
||||||
<artifactId>contrib</artifactId>
|
<artifactId>contrib</artifactId>
|
||||||
<name>TwelveMonkeys » Contrib</name>
|
<name>TwelveMonkeys :: Contrib</name>
|
||||||
<description>
|
<description>
|
||||||
Contributions to TwelveMonkeys and code that doesn't fit anywhere else.
|
Contributions to TwelveMonkeys and code that doesn't fit anywhere else.
|
||||||
</description>
|
</description>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<junit.jupiter.version>5.14.4</junit.jupiter.version>
|
<junit.jupiter.version>5.13.0</junit.jupiter.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-batik</artifactId>
|
<artifactId>imageio-batik</artifactId>
|
||||||
<name>TwelveMonkeys » ImageIO » Batik Plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: Batik Plugin</name>
|
||||||
<description>
|
<description>
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
ImageIO wrapper for the Batik SVG Toolkit, enabling Scalable Vector Graphics (SVG) support.
|
ImageIO wrapper for the Batik SVG Toolkit, enabling Scalable Vector Graphics (SVG) support.
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>commons-io</groupId>
|
<groupId>commons-io</groupId>
|
||||||
<artifactId>commons-io</artifactId>
|
<artifactId>commons-io</artifactId>
|
||||||
<version>2.22.0</version>
|
<version>2.19.0</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|||||||
+1
-46
@@ -36,11 +36,9 @@ import com.twelvemonkeys.lang.SystemUtil;
|
|||||||
import javax.imageio.ImageReader;
|
import javax.imageio.ImageReader;
|
||||||
import javax.imageio.spi.ServiceRegistry;
|
import javax.imageio.spi.ServiceRegistry;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.function.Predicate;
|
|
||||||
|
|
||||||
import static com.twelvemonkeys.imageio.util.IIOUtil.deregisterProvider;
|
import static com.twelvemonkeys.imageio.util.IIOUtil.deregisterProvider;
|
||||||
|
|
||||||
@@ -136,42 +134,10 @@ public final class SVGImageReaderSpi extends ImageReaderSpiBase {
|
|||||||
if (buffer[0] == 's' && buffer[1] == 'v' && buffer[2] == 'g'
|
if (buffer[0] == 's' && buffer[1] == 'v' && buffer[2] == 'g'
|
||||||
&& (Character.isWhitespace((char) buffer[3]) || buffer[3] == ':')) {
|
&& (Character.isWhitespace((char) buffer[3]) || buffer[3] == ':')) {
|
||||||
// It's SVG, identified by root tag
|
// It's SVG, identified by root tag
|
||||||
|
// TODO: Support svg with prefix + recognize namespace (http://www.w3.org/2000/svg)!
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the full tag name (may contain a prefix of any length)
|
|
||||||
final int MAX_TAG_NAME = 256;
|
|
||||||
ByteArrayOutputStream nameBuf = new ByteArrayOutputStream(MAX_TAG_NAME);
|
|
||||||
|
|
||||||
// We already have 4 bytes in 'buffer' (from input.readFully(buffer))
|
|
||||||
int consumedFromBuffer = 0;
|
|
||||||
for (; consumedFromBuffer < buffer.length; consumedFromBuffer++) {
|
|
||||||
byte bb = buffer[consumedFromBuffer];
|
|
||||||
if (bb == '>' || Character.isWhitespace((char) bb) || bb == '/') {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
nameBuf.write(bb);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If tag name not terminated yet, keep reading bytes (within limit)
|
|
||||||
final boolean incompleteTagName = consumedFromBuffer == buffer.length;
|
|
||||||
readBuffer(input, nameBuf, output -> incompleteTagName && output.size() < MAX_TAG_NAME,
|
|
||||||
bb -> bb == '>' || Character.isWhitespace(bb) || bb == '/');
|
|
||||||
|
|
||||||
final String name = nameBuf.toString("US-ASCII");
|
|
||||||
if (name.toLowerCase(Locale.ENGLISH).endsWith(":svg")) {
|
|
||||||
// Scan the rest of the tag attributes until '>' to find the SVG namespace URI
|
|
||||||
ByteArrayOutputStream attrBuf = new ByteArrayOutputStream();
|
|
||||||
final int MAX_ATTR_SCAN = 1024; // safe upper bound to keep it fast
|
|
||||||
readBuffer(input, attrBuf, output -> output.size() < MAX_ATTR_SCAN, bb -> bb == '>');
|
|
||||||
|
|
||||||
// If the tag contains the SVG namespace, it's SVG.
|
|
||||||
if (attrBuf.toString("US-ASCII").matches(
|
|
||||||
".*xmlns:" + name.split(":")[0] + "\\s*=\\s*\"http://www.w3.org/2000/svg\".*")) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the tag is not "svg", this isn't SVG
|
// If the tag is not "svg", this isn't SVG
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -191,17 +157,6 @@ public final class SVGImageReaderSpi extends ImageReaderSpiBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void readBuffer(final ImageInputStream input, final ByteArrayOutputStream buffer,
|
|
||||||
final Predicate<ByteArrayOutputStream> loopCondition, Predicate<Byte> breakCondition) throws IOException {
|
|
||||||
while (loopCondition.test(buffer)) {
|
|
||||||
byte bb = input.readByte();
|
|
||||||
if (breakCondition.test(bb)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
buffer.write(bb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImageReader createReaderInstance(final Object extension) throws IOException {
|
public ImageReader createReaderInstance(final Object extension) throws IOException {
|
||||||
return new SVGImageReader(this);
|
return new SVGImageReader(this);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-4
@@ -56,7 +56,7 @@ public class SVGImageReaderSpiTest {
|
|||||||
"/svg/Android_robot.svg", // Minimal, no xml dec, no namespace
|
"/svg/Android_robot.svg", // Minimal, no xml dec, no namespace
|
||||||
"/svg/batikLogo.svg", // xml dec, comments, namespace
|
"/svg/batikLogo.svg", // xml dec, comments, namespace
|
||||||
"/svg/blue-square.svg", // xml dec, namespace
|
"/svg/blue-square.svg", // xml dec, namespace
|
||||||
"/svg/red-square.svg", // prefixed namespace
|
"/svg/red-square.svg",
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final String[] INVALID_INPUTS = {
|
private static final String[] INVALID_INPUTS = {
|
||||||
@@ -70,9 +70,6 @@ public class SVGImageReaderSpiTest {
|
|||||||
"<!-- ", // #275 Infinite loop issue
|
"<!-- ", // #275 Infinite loop issue
|
||||||
"<?123?>", // #275 Infinite loop issue
|
"<?123?>", // #275 Infinite loop issue
|
||||||
"<svg",
|
"<svg",
|
||||||
"<ns0:svg>", // namespace prefix undefined
|
|
||||||
"<ns0:svg xmlns:ns0=\"foo\">", // not the official svg namespace
|
|
||||||
"<ns0:svg xmlns:ns1=\"http://www.w3.org/2000/svg\">", // mismatching prefix
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<ns0:svg xmlns:ns0="http://www.w3.org/2000/svg" width="100" height="100" id="red-square" version="1.1">
|
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" id="red-square" version="1.1">
|
||||||
<ns0:g id="layer1">
|
<g id="layer1">
|
||||||
<ns0:rect id="rect2985" width="100" height="100" x="0" y="0"
|
<rect id="rect2985" width="100" height="100" x="0" y="0"
|
||||||
style="color:#000000;fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
style="color:#000000;fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||||
</ns0:g>
|
</g>
|
||||||
</ns0:svg>
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 465 B After Width: | Height: | Size: 441 B |
@@ -4,10 +4,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-bmp</artifactId>
|
<artifactId>imageio-bmp</artifactId>
|
||||||
<name>TwelveMonkeys » ImageIO » BMP plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: BMP plugin</name>
|
||||||
<description>ImageIO plugin for Microsoft Device Independent Bitmap (BMP/DIB) format.</description>
|
<description>ImageIO plugin for Microsoft Device Independent Bitmap (BMP/DIB) format.</description>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
|||||||
+24
-11
@@ -32,7 +32,6 @@ package com.twelvemonkeys.imageio.plugins.bmp;
|
|||||||
|
|
||||||
import com.twelvemonkeys.imageio.stream.SubImageOutputStream;
|
import com.twelvemonkeys.imageio.stream.SubImageOutputStream;
|
||||||
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
||||||
import com.twelvemonkeys.imageio.util.SequenceSupport;
|
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
import javax.imageio.IIOException;
|
||||||
import javax.imageio.IIOImage;
|
import javax.imageio.IIOImage;
|
||||||
@@ -65,7 +64,7 @@ public final class ICOImageWriter extends DIBImageWriter {
|
|||||||
private static final int ICO_MAX_DIMENSION = 256;
|
private static final int ICO_MAX_DIMENSION = 256;
|
||||||
private static final int INITIAL_ENTRY_COUNT = 8;
|
private static final int INITIAL_ENTRY_COUNT = 8;
|
||||||
|
|
||||||
private final SequenceSupport sequence = new SequenceSupport();
|
private int sequenceIndex = -1;
|
||||||
|
|
||||||
private ImageWriter pngDelegate;
|
private ImageWriter pngDelegate;
|
||||||
|
|
||||||
@@ -75,7 +74,7 @@ public final class ICOImageWriter extends DIBImageWriter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void resetMembers() {
|
protected void resetMembers() {
|
||||||
sequence.reset();
|
sequenceIndex = -1;
|
||||||
|
|
||||||
if (pngDelegate != null) {
|
if (pngDelegate != null) {
|
||||||
pngDelegate.dispose();
|
pngDelegate.dispose();
|
||||||
@@ -108,12 +107,16 @@ public final class ICOImageWriter extends DIBImageWriter {
|
|||||||
@Override
|
@Override
|
||||||
public void prepareWriteSequence(final IIOMetadata streamMetadata) throws IOException {
|
public void prepareWriteSequence(final IIOMetadata streamMetadata) throws IOException {
|
||||||
assertOutput();
|
assertOutput();
|
||||||
sequence.start();
|
|
||||||
|
if (sequenceIndex >= 0) {
|
||||||
|
throw new IllegalStateException("writeSequence already started");
|
||||||
|
}
|
||||||
|
|
||||||
writeICOHeader();
|
writeICOHeader();
|
||||||
|
|
||||||
// Count: Needs to be updated for each new image
|
// Count: Needs to be updated for each new image
|
||||||
imageOutput.writeShort(0);
|
imageOutput.writeShort(0);
|
||||||
|
sequenceIndex = 0;
|
||||||
|
|
||||||
// TODO: Allow passing the initial size of the directory in the stream metadata?
|
// TODO: Allow passing the initial size of the directory in the stream metadata?
|
||||||
// - as this is much more efficient than growing...
|
// - as this is much more efficient than growing...
|
||||||
@@ -127,19 +130,27 @@ public final class ICOImageWriter extends DIBImageWriter {
|
|||||||
@Override
|
@Override
|
||||||
public void endWriteSequence() {
|
public void endWriteSequence() {
|
||||||
assertOutput();
|
assertOutput();
|
||||||
sequence.end();
|
|
||||||
|
if (sequenceIndex < 0) {
|
||||||
|
throw new IllegalStateException("prepareWriteSequence not called");
|
||||||
|
}
|
||||||
|
|
||||||
|
sequenceIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeToSequence(final IIOImage image, final ImageWriteParam param) throws IOException {
|
public void writeToSequence(final IIOImage image, final ImageWriteParam param) throws IOException {
|
||||||
assertOutput();
|
assertOutput();
|
||||||
int imageIndex = sequence.advance();
|
|
||||||
|
if (sequenceIndex < 0) {
|
||||||
|
throw new IllegalStateException("prepareWriteSequence not called");
|
||||||
|
}
|
||||||
|
|
||||||
if (image.hasRaster()) {
|
if (image.hasRaster()) {
|
||||||
throw new UnsupportedOperationException("Raster not supported");
|
throw new UnsupportedOperationException("Raster not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (imageIndex >= INITIAL_ENTRY_COUNT) {
|
if (sequenceIndex >= INITIAL_ENTRY_COUNT) {
|
||||||
growIfNecessary();
|
growIfNecessary();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +172,7 @@ public final class ICOImageWriter extends DIBImageWriter {
|
|||||||
// Uncompressed, RLE4/RLE8 or PNG compressed
|
// Uncompressed, RLE4/RLE8 or PNG compressed
|
||||||
boolean pngCompression = param != null && "BI_PNG".equals(param.getCompressionType());
|
boolean pngCompression = param != null && "BI_PNG".equals(param.getCompressionType());
|
||||||
|
|
||||||
processImageStarted(imageIndex);
|
processImageStarted(sequenceIndex);
|
||||||
|
|
||||||
if (pngCompression) {
|
if (pngCompression) {
|
||||||
// NOTE: Embedding a PNG in a ICO is slightly different than a BMP with BI_PNG compression,
|
// NOTE: Embedding a PNG in a ICO is slightly different than a BMP with BI_PNG compression,
|
||||||
@@ -187,15 +198,17 @@ public final class ICOImageWriter extends DIBImageWriter {
|
|||||||
|
|
||||||
// Update count
|
// Update count
|
||||||
imageOutput.seek(4);
|
imageOutput.seek(4);
|
||||||
imageOutput.writeShort(imageIndex + 1);
|
imageOutput.writeShort(sequenceIndex + 1);
|
||||||
|
|
||||||
// Write entry
|
// Write entry
|
||||||
int entryPosition = 6 + imageIndex * ENTRY_SIZE;
|
int entryPosition = 6 + sequenceIndex * ENTRY_SIZE;
|
||||||
imageOutput.seek(entryPosition);
|
imageOutput.seek(entryPosition);
|
||||||
|
|
||||||
long size = nextPosition - imageOffset;
|
long size = nextPosition - imageOffset;
|
||||||
writeEntry(width, height, colorModel, (int) size, (int) imageOffset);
|
writeEntry(width, height, colorModel, (int) size, (int) imageOffset);
|
||||||
|
|
||||||
|
sequenceIndex++;
|
||||||
|
|
||||||
imageOutput.seek(nextPosition);
|
imageOutput.seek(nextPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,7 +265,7 @@ public final class ICOImageWriter extends DIBImageWriter {
|
|||||||
pngDelegate.addIIOWriteWarningListener(new IIOWriteWarningListener() {
|
pngDelegate.addIIOWriteWarningListener(new IIOWriteWarningListener() {
|
||||||
@Override
|
@Override
|
||||||
public void warningOccurred(ImageWriter source, int imageIndex, String warning) {
|
public void warningOccurred(ImageWriter source, int imageIndex, String warning) {
|
||||||
processWarningOccurred(sequence.current(), warning);
|
processWarningOccurred(sequenceIndex, warning);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-clippath</artifactId>
|
<artifactId>imageio-clippath</artifactId>
|
||||||
<name>TwelveMonkeys » ImageIO » Photoshop Path Support</name>
|
<name>TwelveMonkeys :: ImageIO :: Photoshop Path Support</name>
|
||||||
<description>
|
<description>
|
||||||
Photoshop Clipping Path Support.
|
Photoshop Clipping Path Support.
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-core</artifactId>
|
<artifactId>imageio-core</artifactId>
|
||||||
<name>TwelveMonkeys » ImageIO » Core</name>
|
<name>TwelveMonkeys :: ImageIO :: Core</name>
|
||||||
<description>
|
<description>
|
||||||
TwelveMonkeys ImageIO core support classes.
|
TwelveMonkeys ImageIO core support classes.
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
+2
-3
@@ -23,7 +23,6 @@ import static com.twelvemonkeys.lang.Validate.notNull;
|
|||||||
* {@link ImageTypeSpecifier}.
|
* {@link ImageTypeSpecifier}.
|
||||||
* Other values or overrides may be specified using the builder.
|
* Other values or overrides may be specified using the builder.
|
||||||
*
|
*
|
||||||
* @see <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.desktop/javax/imageio/metadata/doc-files/standard_metadata.html">Standard (Plug-in Neutral) Metadata Format Specification</a>
|
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
*/
|
*/
|
||||||
public class StandardImageMetadataSupport extends AbstractMetadata {
|
public class StandardImageMetadataSupport extends AbstractMetadata {
|
||||||
@@ -80,11 +79,11 @@ public class StandardImageMetadataSupport extends AbstractMetadata {
|
|||||||
textEntries = builder.textEntries;
|
textEntries = builder.textEntries;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static Builder builder(ImageTypeSpecifier type) {
|
public static Builder builder(ImageTypeSpecifier type) {
|
||||||
return new Builder(type);
|
return new Builder(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static class Builder {
|
public static class Builder {
|
||||||
private final ImageTypeSpecifier type;
|
private final ImageTypeSpecifier type;
|
||||||
private ColorSpaceType colorSpaceType;
|
private ColorSpaceType colorSpaceType;
|
||||||
private boolean blackIsZero = true;
|
private boolean blackIsZero = true;
|
||||||
|
|||||||
@@ -35,8 +35,6 @@ import com.twelvemonkeys.lang.Validate;
|
|||||||
|
|
||||||
import javax.imageio.IIOParam;
|
import javax.imageio.IIOParam;
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import javax.imageio.ImageReadParam;
|
|
||||||
import javax.imageio.ImageWriteParam;
|
|
||||||
import javax.imageio.spi.IIOServiceProvider;
|
import javax.imageio.spi.IIOServiceProvider;
|
||||||
import javax.imageio.spi.ServiceRegistry;
|
import javax.imageio.spi.ServiceRegistry;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
@@ -47,9 +45,7 @@ import java.io.BufferedInputStream;
|
|||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.SortedSet;
|
import java.util.SortedSet;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
|
||||||
@@ -72,7 +68,7 @@ public final class IIOUtil {
|
|||||||
*/
|
*/
|
||||||
public static InputStream createStreamAdapter(final ImageInputStream pStream) {
|
public static InputStream createStreamAdapter(final ImageInputStream pStream) {
|
||||||
// TODO: Include stream start pos?
|
// TODO: Include stream start pos?
|
||||||
// TODO: Skip buffering for known in-memory implementations? pStream.isCachedMemory
|
// TODO: Skip buffering for known in-memory implementations?
|
||||||
return new BufferedInputStream(new IIOInputStreamAdapter(pStream));
|
return new BufferedInputStream(new IIOInputStreamAdapter(pStream));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +82,7 @@ public final class IIOUtil {
|
|||||||
*/
|
*/
|
||||||
public static InputStream createStreamAdapter(final ImageInputStream pStream, final long pLength) {
|
public static InputStream createStreamAdapter(final ImageInputStream pStream, final long pLength) {
|
||||||
// TODO: Include stream start pos?
|
// TODO: Include stream start pos?
|
||||||
// TODO: Skip buffering for known in-memory implementations? pStream.isCachedMemory
|
// TODO: Skip buffering for known in-memory implementations?
|
||||||
return new BufferedInputStream(new IIOInputStreamAdapter(pStream, pLength));
|
return new BufferedInputStream(new IIOInputStreamAdapter(pStream, pLength));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,115 +359,4 @@ public final class IIOUtil {
|
|||||||
System.arraycopy(srcRow, srcPos + x, destRow, destPos + x / samplePeriod, pixelStride);
|
System.arraycopy(srcRow, srcPos + x, destRow, destPos + x / samplePeriod, pixelStride);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies all the standard param values from source to destination.
|
|
||||||
* <p>
|
|
||||||
* Typical use (in some imaginary {@code FooImageWriter} class):
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* ImageWriteParam param = ...
|
|
||||||
* FooImageWriteparam fooParam = param instanceof FooImageWriteParam
|
|
||||||
* ? (FooImageWriteParam) param
|
|
||||||
* : copyStandardParams(param, getDefaultWriteParam());
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* May also be useful for {@code ImageReader}s that delegate reading to other plugins
|
|
||||||
* (like a TIFF plugin delegating JPEG format decoding to a {@code JPEGImageReader}).
|
|
||||||
*
|
|
||||||
* @param source the source parameter, may be {@code null}
|
|
||||||
* @param destination the destination parameter
|
|
||||||
* @return destination
|
|
||||||
*
|
|
||||||
* @param <T> the plugin specific subclass of {@code IIOParam}
|
|
||||||
*
|
|
||||||
* @throws NullPointerException if destination is {@code null}
|
|
||||||
*/
|
|
||||||
public static <T extends IIOParam> T copyStandardParams(IIOParam source, T destination) {
|
|
||||||
Objects.requireNonNull(destination);
|
|
||||||
Validate.isTrue(source != destination, "source must be different from destination");
|
|
||||||
|
|
||||||
if (source != null) {
|
|
||||||
copyIIOParams(source, destination);
|
|
||||||
|
|
||||||
// TODO: API & usage... Is it ever useful to copy from a read to a write param or vice versa?
|
|
||||||
// If not, maybe throw an IllegalArgumentException instead
|
|
||||||
|
|
||||||
if (source instanceof ImageReadParam && destination instanceof ImageReadParam) {
|
|
||||||
copyImageReadParams((ImageReadParam) source, (ImageReadParam) destination);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (source instanceof ImageWriteParam && destination instanceof ImageWriteParam) {
|
|
||||||
copyImageWriteParams((ImageWriteParam) source, (ImageWriteParam) destination);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return destination;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void copyImageWriteParams(ImageWriteParam source, ImageWriteParam destination) {
|
|
||||||
// TODO: Usage... It's very unlikely that compression settings of one plugin is compatible with another...
|
|
||||||
// Is the the below useful?
|
|
||||||
// Also, is it okay to just silently ignore settings from one format that isn't compatible with another?
|
|
||||||
|
|
||||||
// Quirky API, we can't query for compression mode, unless source.canWriteCompressed is true...
|
|
||||||
if (source.canWriteCompressed() && destination.canWriteCompressed()) {
|
|
||||||
int compressionMode = source.getCompressionMode();
|
|
||||||
destination.setCompressionMode(compressionMode);
|
|
||||||
|
|
||||||
if (compressionMode == ImageWriteParam.MODE_EXPLICIT
|
|
||||||
&& source.getCompressionType() != null
|
|
||||||
&& Arrays.asList(destination.getCompressionTypes()).contains(source.getCompressionType())) {
|
|
||||||
destination.setCompressionType(source.getCompressionType());
|
|
||||||
destination.setCompressionQuality(source.getCompressionQuality());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (source.canWriteProgressive() && destination.canWriteProgressive()) {
|
|
||||||
destination.setProgressiveMode(source.getProgressiveMode());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (source.canWriteTiles() && destination.canWriteTiles()) {
|
|
||||||
int tilingMode = source.getTilingMode();
|
|
||||||
destination.setTilingMode(tilingMode);
|
|
||||||
|
|
||||||
if (tilingMode == ImageWriteParam.MODE_EXPLICIT) {
|
|
||||||
// TODO: What if source can offset (and has offsets) and dest can't? Is it ok to just ignore the setting?
|
|
||||||
boolean canWriteOffsetTiles = source.canOffsetTiles() && destination.canOffsetTiles();
|
|
||||||
|
|
||||||
destination.setTiling(
|
|
||||||
source.getTileWidth(), source.getTileHeight(),
|
|
||||||
canWriteOffsetTiles ? source.getTileGridXOffset() : 0,
|
|
||||||
canWriteOffsetTiles ? source.getTileGridYOffset() : 0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void copyImageReadParams(ImageReadParam source, ImageReadParam destination) {
|
|
||||||
destination.setDestination(source.getDestination());
|
|
||||||
destination.setDestinationBands(source.getDestinationBands());
|
|
||||||
|
|
||||||
if (destination.canSetSourceRenderSize()) {
|
|
||||||
destination.setSourceRenderSize(source.getSourceRenderSize());
|
|
||||||
}
|
|
||||||
|
|
||||||
destination.setSourceProgressivePasses(
|
|
||||||
source.getSourceMinProgressivePass(),
|
|
||||||
source.getSourceMaxProgressivePass()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void copyIIOParams(IIOParam source, IIOParam destination) {
|
|
||||||
destination.setController(source.getController());
|
|
||||||
destination.setSourceSubsampling(
|
|
||||||
source.getSourceXSubsampling(), source.getSourceYSubsampling(),
|
|
||||||
source.getSubsamplingXOffset(), source.getSubsamplingYOffset()
|
|
||||||
);
|
|
||||||
destination.setSourceRegion(source.getSourceRegion());
|
|
||||||
destination.setSourceBands(source.getSourceBands());
|
|
||||||
destination.setDestinationOffset(source.getDestinationOffset());
|
|
||||||
destination.setDestinationType(source.getDestinationType());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
-115
@@ -1,115 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2026, Harald Kuhr
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* * Redistributions of source code must retain the above copyright notice, this
|
|
||||||
* list of conditions and the following disclaimer.
|
|
||||||
*
|
|
||||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* * Neither the name of the copyright holder nor the names of its
|
|
||||||
* contributors may be used to endorse or promote products derived from
|
|
||||||
* this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.twelvemonkeys.imageio.util;
|
|
||||||
|
|
||||||
import javax.imageio.IIOImage;
|
|
||||||
import javax.imageio.ImageWriteParam;
|
|
||||||
import javax.imageio.ImageWriter;
|
|
||||||
import javax.imageio.metadata.IIOMetadata;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A tiny utility class that keeps state for sequences.
|
|
||||||
* For use by {@code ImageWriter} implementations that supports sequence (multiple images in same stream).
|
|
||||||
*
|
|
||||||
* @see ImageWriter#canWriteSequence()
|
|
||||||
*/
|
|
||||||
public final class SequenceSupport {
|
|
||||||
// Initial state, no sequence running
|
|
||||||
private int index = -1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets the sequence to initial state, regardless of the current sequence state.
|
|
||||||
*/
|
|
||||||
public void reset() {
|
|
||||||
index = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts a new sequence.
|
|
||||||
*
|
|
||||||
* @throws IllegalStateException if a sequence is already running.
|
|
||||||
* @see ImageWriter#prepareWriteSequence(IIOMetadata)
|
|
||||||
*/
|
|
||||||
public void start() {
|
|
||||||
if (index >= 0) {
|
|
||||||
throw new IllegalStateException("prepareWriteSequence already invoked");
|
|
||||||
}
|
|
||||||
|
|
||||||
index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Advances the current sequence.
|
|
||||||
*
|
|
||||||
* @return the current sequence index.
|
|
||||||
* @throws IllegalStateException if a sequence is not running.
|
|
||||||
* @see ImageWriter#writeToSequence(IIOImage, ImageWriteParam)
|
|
||||||
*/
|
|
||||||
public int advance() {
|
|
||||||
if (index < 0) {
|
|
||||||
throw new IllegalStateException("prepareWriteSequence not invoked");
|
|
||||||
}
|
|
||||||
|
|
||||||
return index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the current sequence index.
|
|
||||||
*
|
|
||||||
* @return the current sequence index, or {@code -1} if a sequence is not running.
|
|
||||||
*/
|
|
||||||
public int current() {
|
|
||||||
// This method does not throw IllegalStateException, to allow
|
|
||||||
// ImageWriters to use the index in cases that may or may not
|
|
||||||
// happen "inside" a sequence.
|
|
||||||
// I'm not entirely sure if this is a good idea...
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ends the current sequence.
|
|
||||||
* The sequence is reset to initial state, and a new sequence may be started.
|
|
||||||
*
|
|
||||||
* @return the current (last) sequence index
|
|
||||||
* @throws IllegalStateException if a sequence is not running.
|
|
||||||
* @see ImageWriter#endWriteSequence()
|
|
||||||
*/
|
|
||||||
public int end() {
|
|
||||||
if (index < 0) {
|
|
||||||
throw new IllegalStateException("prepareWriteSequence not invoked");
|
|
||||||
}
|
|
||||||
|
|
||||||
int last = index;
|
|
||||||
index = -1;
|
|
||||||
|
|
||||||
return last;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +1,8 @@
|
|||||||
package com.twelvemonkeys.imageio.util;
|
package com.twelvemonkeys.imageio.util;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
import java.awt.Point;
|
|
||||||
import java.awt.Rectangle;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
|
|
||||||
import javax.imageio.ImageReadParam;
|
|
||||||
import javax.imageio.ImageTypeSpecifier;
|
|
||||||
import javax.imageio.ImageWriteParam;
|
|
||||||
import javax.imageio.plugins.bmp.BMPImageWriteParam;
|
|
||||||
import javax.imageio.plugins.jpeg.JPEGImageReadParam;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* IIOUtilTest
|
* IIOUtilTest
|
||||||
*/
|
*/
|
||||||
@@ -215,222 +204,4 @@ public class IIOUtilTest {
|
|||||||
private int divCeil(int numerator, int denominator) {
|
private int divCeil(int numerator, int denominator) {
|
||||||
return (numerator + denominator - 1) / denominator;
|
return (numerator + denominator - 1) / denominator;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void copyStandardParamsDestinationNull() {
|
|
||||||
ImageReadParam param = new ImageReadParam();
|
|
||||||
|
|
||||||
assertThrows(NullPointerException.class, () -> IIOUtil.copyStandardParams(null, null));
|
|
||||||
assertThrows(NullPointerException.class, () -> IIOUtil.copyStandardParams(param, null));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void copyStandardParamsSame() {
|
|
||||||
ImageReadParam param = new ImageReadParam();
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> IIOUtil.copyStandardParams(param, param));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void copyStandardParamsSourceNull() {
|
|
||||||
ImageReadParam param = new ImageReadParam() {
|
|
||||||
@Override
|
|
||||||
public void setSourceRegion(Rectangle sourceRegion) {
|
|
||||||
fail("Should not be invoked");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
assertSame(param, IIOUtil.copyStandardParams(null, param));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void copyStandardParamsImageReadParam() {
|
|
||||||
int sourceXSubsampling = 3;
|
|
||||||
int sourceYSubsampling = 4;
|
|
||||||
int subsamplingXOffset = 1;
|
|
||||||
int subsamplingYOffset = 2;
|
|
||||||
Rectangle sourceRegion = new Rectangle(1, 2, 42, 43);
|
|
||||||
int[] sourceBands = { 0, 1, 2 };
|
|
||||||
|
|
||||||
Point destinationOffset = new Point(7, 9);
|
|
||||||
int[] destinationBands = { 2, 1, 0 };
|
|
||||||
|
|
||||||
ImageReadParam sourceParam = new ImageReadParam();
|
|
||||||
sourceParam.setSourceRegion(sourceRegion);
|
|
||||||
sourceParam.setSourceSubsampling(sourceXSubsampling, sourceYSubsampling, subsamplingXOffset, subsamplingYOffset);
|
|
||||||
sourceParam.setSourceBands(sourceBands);
|
|
||||||
|
|
||||||
sourceParam.setDestinationOffset(destinationOffset);
|
|
||||||
sourceParam.setDestinationBands(destinationBands);
|
|
||||||
|
|
||||||
JPEGImageReadParam jpegParam = IIOUtil.copyStandardParams(sourceParam, new JPEGImageReadParam());
|
|
||||||
|
|
||||||
assertEquals(sourceRegion, jpegParam.getSourceRegion());
|
|
||||||
assertEquals(sourceXSubsampling, jpegParam.getSourceXSubsampling());
|
|
||||||
assertEquals(sourceYSubsampling, jpegParam.getSourceYSubsampling());
|
|
||||||
assertEquals(subsamplingXOffset, jpegParam.getSubsamplingXOffset());
|
|
||||||
assertEquals(subsamplingYOffset, jpegParam.getSubsamplingYOffset());
|
|
||||||
assertArrayEquals(sourceBands, jpegParam.getSourceBands());
|
|
||||||
|
|
||||||
assertEquals(destinationOffset, jpegParam.getDestinationOffset());
|
|
||||||
assertArrayEquals(destinationBands, jpegParam.getDestinationBands());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void copyStandardParamsImageReadParamDestination() {
|
|
||||||
// Destination and destination type is mutually exclusive
|
|
||||||
BufferedImage destination = new BufferedImage(2, 2, BufferedImage.TYPE_INT_ARGB);
|
|
||||||
|
|
||||||
ImageReadParam sourceParam = new ImageReadParam();
|
|
||||||
sourceParam.setDestination(destination);
|
|
||||||
|
|
||||||
assertEquals(destination, IIOUtil.copyStandardParams(sourceParam, new JPEGImageReadParam()).getDestination());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void copyStandardParamsImageReadParamDestinationType() {
|
|
||||||
// Destination and destination type is mutually exclusive
|
|
||||||
ImageTypeSpecifier destinationType = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY);
|
|
||||||
|
|
||||||
ImageReadParam sourceParam = new ImageReadParam();
|
|
||||||
sourceParam.setDestinationType(destinationType);
|
|
||||||
|
|
||||||
assertEquals(destinationType, IIOUtil.copyStandardParams(sourceParam, new JPEGImageReadParam()).getDestinationType());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void copyStandardParamsReadToWrite() {
|
|
||||||
int sourceXSubsampling = 3;
|
|
||||||
int sourceYSubsampling = 4;
|
|
||||||
int subsamplingXOffset = 1;
|
|
||||||
int subsamplingYOffset = 2;
|
|
||||||
Rectangle sourceRegion = new Rectangle(1, 2, 42, 43);
|
|
||||||
int[] sourceBands = { 0, 1, 2 };
|
|
||||||
|
|
||||||
Point destinationOffset = new Point(7, 9);
|
|
||||||
|
|
||||||
ImageWriteParam sourceParam = new ImageWriteParam(null);
|
|
||||||
sourceParam.setSourceRegion(sourceRegion);
|
|
||||||
sourceParam.setSourceSubsampling(sourceXSubsampling, sourceYSubsampling, subsamplingXOffset, subsamplingYOffset);
|
|
||||||
sourceParam.setSourceBands(sourceBands);
|
|
||||||
|
|
||||||
sourceParam.setDestinationOffset(destinationOffset);
|
|
||||||
|
|
||||||
JPEGImageReadParam jpegParam = IIOUtil.copyStandardParams(sourceParam, new JPEGImageReadParam());
|
|
||||||
|
|
||||||
assertEquals(sourceRegion, jpegParam.getSourceRegion());
|
|
||||||
assertEquals(sourceXSubsampling, jpegParam.getSourceXSubsampling());
|
|
||||||
assertEquals(sourceYSubsampling, jpegParam.getSourceYSubsampling());
|
|
||||||
assertEquals(subsamplingXOffset, jpegParam.getSubsamplingXOffset());
|
|
||||||
assertEquals(subsamplingYOffset, jpegParam.getSubsamplingYOffset());
|
|
||||||
assertArrayEquals(sourceBands, jpegParam.getSourceBands());
|
|
||||||
|
|
||||||
assertEquals(destinationOffset, jpegParam.getDestinationOffset());
|
|
||||||
assertNull(jpegParam.getDestinationBands()); // Only in read param
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void copyStandardParamsImageWriteParam() {
|
|
||||||
int sourceXSubsampling = 3;
|
|
||||||
int sourceYSubsampling = 4;
|
|
||||||
int subsamplingXOffset = 1;
|
|
||||||
int subsamplingYOffset = 2;
|
|
||||||
Rectangle sourceRegion = new Rectangle(1, 2, 42, 43);
|
|
||||||
int[] sourceBands = { 0, 1, 2 };
|
|
||||||
|
|
||||||
Point destinationOffset = new Point(7, 9);
|
|
||||||
|
|
||||||
ImageWriteParam sourceParam = new ImageWriteParam(null);
|
|
||||||
sourceParam.setSourceRegion(sourceRegion);
|
|
||||||
sourceParam.setSourceSubsampling(sourceXSubsampling, sourceYSubsampling, subsamplingXOffset, subsamplingYOffset);
|
|
||||||
sourceParam.setSourceBands(sourceBands);
|
|
||||||
|
|
||||||
sourceParam.setDestinationOffset(destinationOffset);
|
|
||||||
|
|
||||||
BMPImageWriteParam fooParam = IIOUtil.copyStandardParams(sourceParam, new BMPImageWriteParam());
|
|
||||||
|
|
||||||
assertEquals(sourceRegion, fooParam.getSourceRegion());
|
|
||||||
assertEquals(sourceXSubsampling, fooParam.getSourceXSubsampling());
|
|
||||||
assertEquals(sourceYSubsampling, fooParam.getSourceYSubsampling());
|
|
||||||
assertEquals(subsamplingXOffset, fooParam.getSubsamplingXOffset());
|
|
||||||
assertEquals(subsamplingYOffset, fooParam.getSubsamplingYOffset());
|
|
||||||
assertArrayEquals(sourceBands, fooParam.getSourceBands());
|
|
||||||
|
|
||||||
assertEquals(destinationOffset, fooParam.getDestinationOffset());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void copyStandardParamsImageWriteParamEverything() {
|
|
||||||
int sourceXSubsampling = 3;
|
|
||||||
int sourceYSubsampling = 4;
|
|
||||||
int subsamplingXOffset = 1;
|
|
||||||
int subsamplingYOffset = 2;
|
|
||||||
Rectangle sourceRegion = new Rectangle(1, 2, 42, 43);
|
|
||||||
int[] sourceBands = { 0, 1, 2 };
|
|
||||||
|
|
||||||
Point destinationOffset = new Point(7, 9);
|
|
||||||
|
|
||||||
String compressionType = "Foo";
|
|
||||||
float quality = 0.42f;
|
|
||||||
|
|
||||||
ImageWriteParam sourceParam = new ImageWriteParam() {
|
|
||||||
{
|
|
||||||
canWriteProgressive = true;
|
|
||||||
|
|
||||||
canWriteTiles = true;
|
|
||||||
canOffsetTiles = true;
|
|
||||||
|
|
||||||
canWriteCompressed = true;
|
|
||||||
compressionTypes = new String[] { "Foo", "Bar" };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
sourceParam.setSourceRegion(sourceRegion);
|
|
||||||
sourceParam.setSourceSubsampling(sourceXSubsampling, sourceYSubsampling, subsamplingXOffset, subsamplingYOffset);
|
|
||||||
sourceParam.setSourceBands(sourceBands);
|
|
||||||
|
|
||||||
sourceParam.setDestinationOffset(destinationOffset);
|
|
||||||
|
|
||||||
sourceParam.setProgressiveMode(ImageWriteParam.MODE_DEFAULT); // Default is COPY_FROM_METADATA...
|
|
||||||
sourceParam.setTilingMode(ImageWriteParam.MODE_EXPLICIT);
|
|
||||||
sourceParam.setTiling(1, 2, 3, 4);
|
|
||||||
sourceParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
|
||||||
sourceParam.setCompressionType(compressionType);
|
|
||||||
sourceParam.setCompressionQuality(quality);
|
|
||||||
|
|
||||||
FooImageWriteParam fooParam = IIOUtil.copyStandardParams(sourceParam, new FooImageWriteParam());
|
|
||||||
|
|
||||||
assertEquals(sourceRegion, fooParam.getSourceRegion());
|
|
||||||
assertEquals(sourceXSubsampling, fooParam.getSourceXSubsampling());
|
|
||||||
assertEquals(sourceYSubsampling, fooParam.getSourceYSubsampling());
|
|
||||||
assertEquals(subsamplingXOffset, fooParam.getSubsamplingXOffset());
|
|
||||||
assertEquals(subsamplingYOffset, fooParam.getSubsamplingYOffset());
|
|
||||||
assertArrayEquals(sourceBands, fooParam.getSourceBands());
|
|
||||||
|
|
||||||
assertEquals(destinationOffset, fooParam.getDestinationOffset());
|
|
||||||
|
|
||||||
assertEquals(ImageWriteParam.MODE_DEFAULT, fooParam.getProgressiveMode());
|
|
||||||
|
|
||||||
assertEquals(ImageWriteParam.MODE_EXPLICIT, fooParam.getTilingMode());
|
|
||||||
assertEquals(1, fooParam.getTileWidth());
|
|
||||||
assertEquals(2, fooParam.getTileHeight());
|
|
||||||
assertEquals(3, fooParam.getTileGridXOffset());
|
|
||||||
assertEquals(4, fooParam.getTileGridYOffset());
|
|
||||||
|
|
||||||
assertEquals(ImageWriteParam.MODE_EXPLICIT, fooParam.getCompressionMode());
|
|
||||||
assertEquals(compressionType, fooParam.getCompressionType());
|
|
||||||
assertEquals(quality, fooParam.getCompressionQuality());
|
|
||||||
}
|
|
||||||
|
|
||||||
// A basic param that supports "everything"
|
|
||||||
static class FooImageWriteParam extends ImageWriteParam {
|
|
||||||
FooImageWriteParam() {
|
|
||||||
canWriteProgressive = true;
|
|
||||||
|
|
||||||
canWriteTiles = true;
|
|
||||||
canOffsetTiles = true;
|
|
||||||
|
|
||||||
canWriteCompressed = true;
|
|
||||||
compressionType = "Unset";
|
|
||||||
compressionTypes = new String[] { "Bar", "Foo" };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+8
-46
@@ -34,7 +34,6 @@ import com.twelvemonkeys.imageio.stream.URLImageInputStreamSpi;
|
|||||||
|
|
||||||
import org.mockito.InOrder;
|
import org.mockito.InOrder;
|
||||||
|
|
||||||
import javax.imageio.IIOImage;
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import javax.imageio.ImageWriteParam;
|
import javax.imageio.ImageWriteParam;
|
||||||
import javax.imageio.ImageWriter;
|
import javax.imageio.ImageWriter;
|
||||||
@@ -85,7 +84,6 @@ public abstract class ImageWriterAbstractTest<T extends ImageWriter> {
|
|||||||
|
|
||||||
protected static BufferedImage drawSomething(final BufferedImage image) {
|
protected static BufferedImage drawSomething(final BufferedImage image) {
|
||||||
Graphics2D g = image.createGraphics();
|
Graphics2D g = image.createGraphics();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int width = image.getWidth();
|
int width = image.getWidth();
|
||||||
int height = image.getHeight();
|
int height = image.getHeight();
|
||||||
@@ -133,54 +131,18 @@ public abstract class ImageWriterAbstractTest<T extends ImageWriter> {
|
|||||||
public void testWrite() throws IOException {
|
public void testWrite() throws IOException {
|
||||||
ImageWriter writer = createWriter();
|
ImageWriter writer = createWriter();
|
||||||
|
|
||||||
try {
|
for (RenderedImage testData : getTestData()) {
|
||||||
for (RenderedImage testData : getTestData()) {
|
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
try (ImageOutputStream stream = ImageIO.createImageOutputStream(buffer)) {
|
try (ImageOutputStream stream = ImageIO.createImageOutputStream(buffer)) {
|
||||||
writer.setOutput(stream);
|
writer.setOutput(stream);
|
||||||
writer.write(drawSomething((BufferedImage) testData));
|
writer.write(drawSomething((BufferedImage) testData));
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
throw new AssertionError(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
assertTrue(buffer.size() > 0, "No image data written");
|
|
||||||
}
|
}
|
||||||
}
|
catch (IOException e) {
|
||||||
finally {
|
throw new AssertionError(e.getMessage(), e);
|
||||||
writer.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testWriteRaster() throws IOException {
|
|
||||||
ImageWriter writer = createWriter();
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (!writer.canWriteRasters()) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageWriteParam param = writer.getDefaultWriteParam();
|
assertTrue(buffer.size() > 0, "No image data written");
|
||||||
|
|
||||||
for (RenderedImage testData : getTestData()) {
|
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
try (ImageOutputStream stream = ImageIO.createImageOutputStream(buffer)) {
|
|
||||||
writer.setOutput(stream);
|
|
||||||
|
|
||||||
writer.write(null, new IIOImage(testData.getTile(0, 0), null, null), param);
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
throw new AssertionError(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
assertTrue(buffer.size() > 0, "No image data written");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
writer.dispose();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-89
@@ -1,89 +0,0 @@
|
|||||||
package com.twelvemonkeys.imageio.util;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
class SequenceSupportTest {
|
|
||||||
@Test
|
|
||||||
void happyCase() {
|
|
||||||
SequenceSupport sequence = new SequenceSupport();
|
|
||||||
|
|
||||||
sequence.start();
|
|
||||||
assertEquals(0, sequence.current());
|
|
||||||
|
|
||||||
for (int i = 0; i < Byte.MAX_VALUE; i++) {
|
|
||||||
assertEquals(i, sequence.advance());
|
|
||||||
assertEquals(i + 1, sequence.current());
|
|
||||||
}
|
|
||||||
|
|
||||||
assertEquals(127, sequence.end());
|
|
||||||
assertEquals(-1, sequence.current());
|
|
||||||
assertThrows(IllegalStateException.class, sequence::advance);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void reset() {
|
|
||||||
SequenceSupport sequence = new SequenceSupport();
|
|
||||||
sequence.reset();
|
|
||||||
|
|
||||||
assertEquals(-1, sequence.current());
|
|
||||||
assertThrows(IllegalStateException.class, sequence::end);
|
|
||||||
|
|
||||||
sequence.start();
|
|
||||||
sequence.reset();
|
|
||||||
|
|
||||||
assertEquals(-1, sequence.current());
|
|
||||||
assertThrows(IllegalStateException.class, sequence::end);
|
|
||||||
|
|
||||||
sequence.start();
|
|
||||||
sequence.advance();
|
|
||||||
sequence.reset();
|
|
||||||
|
|
||||||
assertEquals(-1, sequence.current());
|
|
||||||
assertThrows(IllegalStateException.class, sequence::end);
|
|
||||||
|
|
||||||
sequence.start();
|
|
||||||
sequence.end();
|
|
||||||
sequence.reset();
|
|
||||||
|
|
||||||
assertEquals(-1, sequence.current());
|
|
||||||
assertThrows(IllegalStateException.class, sequence::end);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void startEnd() {
|
|
||||||
SequenceSupport sequence = new SequenceSupport();
|
|
||||||
sequence.start();
|
|
||||||
sequence.end();
|
|
||||||
|
|
||||||
assertEquals(-1, sequence.current());
|
|
||||||
assertThrows(IllegalStateException.class, sequence::end);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void startAlreadyStarted() {
|
|
||||||
SequenceSupport sequence = new SequenceSupport();
|
|
||||||
sequence.start();
|
|
||||||
|
|
||||||
assertThrows(IllegalStateException.class, sequence::start);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void advanceNotStarted() {
|
|
||||||
SequenceSupport sequence = new SequenceSupport();
|
|
||||||
assertThrows(IllegalStateException.class, sequence::advance);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void currentNotStarted() {
|
|
||||||
SequenceSupport sequence = new SequenceSupport();
|
|
||||||
assertEquals(-1, sequence.current());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void endNotStarted() {
|
|
||||||
SequenceSupport sequence = new SequenceSupport();
|
|
||||||
assertThrows(IllegalStateException.class, sequence::end);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,10 +4,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-dds</artifactId>
|
<artifactId>imageio-dds</artifactId>
|
||||||
<name>TwelveMonkeys » ImageIO » DDS plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: DDS plugin</name>
|
||||||
<description>
|
<description>
|
||||||
ImageIO plugin for Microsoft Direct DrawSurface (DDS).
|
ImageIO plugin for Microsoft Direct DrawSurface (DDS).
|
||||||
</description>
|
</description>
|
||||||
@@ -43,8 +43,6 @@
|
|||||||
<Provide-Capability>
|
<Provide-Capability>
|
||||||
osgi.serviceloader;
|
osgi.serviceloader;
|
||||||
osgi.serviceloader=javax.imageio.spi.ImageReaderSpi
|
osgi.serviceloader=javax.imageio.spi.ImageReaderSpi
|
||||||
osgi.serviceloader;
|
|
||||||
osgi.serviceloader=javax.imageio.spi.ImageWriterSpi
|
|
||||||
</Provide-Capability>
|
</Provide-Capability>
|
||||||
</instructions>
|
</instructions>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|||||||
-11
@@ -1,11 +0,0 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.dds;
|
|
||||||
|
|
||||||
enum BlockCompression {
|
|
||||||
BC1,
|
|
||||||
BC2,
|
|
||||||
BC3,
|
|
||||||
BC4,
|
|
||||||
BC5,
|
|
||||||
// BC6H,
|
|
||||||
// BC7
|
|
||||||
}
|
|
||||||
@@ -30,35 +30,22 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.dds;
|
package com.twelvemonkeys.imageio.plugins.dds;
|
||||||
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
interface DDS {
|
interface DDS {
|
||||||
int MAGIC = 'D' + ('D' << 8) + ('S' << 16) + (' ' << 24); // Little-Endian
|
byte[] MAGIC = new byte[]{'D', 'D', 'S', ' '};
|
||||||
|
|
||||||
int HEADER_SIZE = 124;
|
int HEADER_SIZE = 124;
|
||||||
int PIXELFORMAT_SIZE = 32;
|
|
||||||
|
|
||||||
// Header Flags
|
// Header Flags
|
||||||
int FLAG_CAPS = 1; // Required in every .dds file.
|
int FLAG_CAPS = 0x1; // Required in every .dds file.
|
||||||
int FLAG_HEIGHT = 1 << 1; // Required in every .dds file.
|
int FLAG_HEIGHT = 0x2; // Required in every .dds file.
|
||||||
int FLAG_WIDTH = 1 << 2; // Required in every .dds file.
|
int FLAG_WIDTH = 0x4; // Required in every .dds file.
|
||||||
int FLAG_PIXELFORMAT = 1 << 12; // Required in every .dds file.
|
int FLAG_PITCH = 0x8; // Required when pitch is provided for an uncompressed texture.
|
||||||
int FLAG_PITCH = 1 << 3; // Required when pitch is provided for an uncompressed texture.
|
int FLAG_PIXELFORMAT = 0x1000; // Required in every .dds file.
|
||||||
int FLAG_MIPMAPCOUNT = 1 << 17; // Required in a mipmapped texture.
|
int FLAG_MIPMAPCOUNT = 0x20000; // Required in a mipmapped texture.
|
||||||
int FLAG_LINEARSIZE = 1 << 19; // Required when pitch is provided for a compressed texture.
|
int FLAG_LINEARSIZE = 0x80000; // Required when pitch is provided for a compressed texture.
|
||||||
int FLAG_DEPTH = 1 << 23; // Required in a depth texture.
|
int FLAG_DEPTH = 0x800000; // Required in a depth texture.
|
||||||
|
|
||||||
// Pixel Format Flags
|
// Pixel Format Flags
|
||||||
int PIXEL_FORMAT_FLAG_ALPHAPIXELS = 0x1;
|
|
||||||
int PIXEL_FORMAT_FLAG_ALPHA = 0x2;
|
|
||||||
int PIXEL_FORMAT_FLAG_FOURCC = 0x04;
|
int PIXEL_FORMAT_FLAG_FOURCC = 0x04;
|
||||||
int PIXEL_FORMAT_FLAG_RGB = 0x40;
|
int PIXEL_FORMAT_FLAG_RGB = 0x40;
|
||||||
|
|
||||||
//DX10 Resource Dimensions
|
|
||||||
int D3D10_RESOURCE_DIMENSION_TEXTURE2D = 3;
|
|
||||||
|
|
||||||
//dwCaps
|
|
||||||
int DDSCAPS_COMPLEX = 0x8;
|
|
||||||
int DDSCAPS_MIPMAP = 0x400000;
|
|
||||||
int DDSCAPS_TEXTURE = 0x1000;
|
|
||||||
}
|
}
|
||||||
|
|||||||
+40
-121
@@ -30,29 +30,16 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.dds;
|
package com.twelvemonkeys.imageio.plugins.dds;
|
||||||
|
|
||||||
import static com.twelvemonkeys.imageio.plugins.dds.DDSReader.A1R5G5B5_MASKS;
|
|
||||||
import static com.twelvemonkeys.imageio.plugins.dds.DDSReader.A4R4G4B4_MASKS;
|
|
||||||
import static com.twelvemonkeys.imageio.plugins.dds.DDSReader.A8B8G8R8_MASKS;
|
|
||||||
import static com.twelvemonkeys.imageio.plugins.dds.DDSReader.A8R8G8B8_MASKS;
|
|
||||||
import static com.twelvemonkeys.imageio.plugins.dds.DDSReader.R5G6B5_MASKS;
|
|
||||||
import static com.twelvemonkeys.imageio.plugins.dds.DDSReader.R8G8B8_MASKS;
|
|
||||||
import static com.twelvemonkeys.imageio.plugins.dds.DDSReader.X1R5G5B5_MASKS;
|
|
||||||
import static com.twelvemonkeys.imageio.plugins.dds.DDSReader.X4R4G4B4_MASKS;
|
|
||||||
import static com.twelvemonkeys.imageio.plugins.dds.DDSReader.X8B8G8R8_MASKS;
|
|
||||||
import static com.twelvemonkeys.imageio.plugins.dds.DDSReader.X8R8G8B8_MASKS;
|
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
import javax.imageio.IIOException;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.math.BigInteger;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
|
||||||
* @see <a href="https://learn.microsoft.com/en-us/windows/win32/direct3ddds/dds-header">DDS_HEADER structure</a>
|
|
||||||
* @see <a href="https://learn.microsoft.com/en-us/windows/win32/direct3ddds/dx-graphics-dds-pguide">Programming Guide for DDS</a>
|
|
||||||
*/
|
|
||||||
final class DDSHeader {
|
final class DDSHeader {
|
||||||
|
|
||||||
|
// https://learn.microsoft.com/en-us/windows/win32/direct3ddds/dx-graphics-dds-pguide
|
||||||
private int flags;
|
private int flags;
|
||||||
|
|
||||||
private int mipMapCount;
|
private int mipMapCount;
|
||||||
@@ -66,12 +53,19 @@ final class DDSHeader {
|
|||||||
private int blueMask;
|
private int blueMask;
|
||||||
private int alphaMask;
|
private int alphaMask;
|
||||||
|
|
||||||
DXT10Header dxt10Header;
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
static DDSHeader read(final ImageInputStream imageInput) throws IOException {
|
static DDSHeader read(final ImageInputStream imageInput) throws IOException {
|
||||||
DDSHeader header = new DDSHeader();
|
DDSHeader header = new DDSHeader();
|
||||||
|
|
||||||
|
// Read MAGIC bytes [0,3]
|
||||||
|
byte[] magic = new byte[DDS.MAGIC.length];
|
||||||
|
imageInput.readFully(magic);
|
||||||
|
if (!Arrays.equals(DDS.MAGIC, magic)) {
|
||||||
|
throw new IIOException(String.format("Not a DDS file. Expected DDS magic 0x%08x', read 0x%08x", new BigInteger(DDS.MAGIC), new BigInteger(magic)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// DDS_HEADER structure
|
||||||
|
// https://learn.microsoft.com/en-us/windows/win32/direct3ddds/dds-header
|
||||||
int dwSize = imageInput.readInt(); // [4,7]
|
int dwSize = imageInput.readInt(); // [4,7]
|
||||||
if (dwSize != DDS.HEADER_SIZE) {
|
if (dwSize != DDS.HEADER_SIZE) {
|
||||||
throw new IIOException(String.format("Invalid DDS header size (expected %d): %d", DDS.HEADER_SIZE, dwSize));
|
throw new IIOException(String.format("Invalid DDS header size (expected %d): %d", DDS.HEADER_SIZE, dwSize));
|
||||||
@@ -79,9 +73,11 @@ final class DDSHeader {
|
|||||||
|
|
||||||
// Verify flags
|
// Verify flags
|
||||||
header.flags = imageInput.readInt(); // [8,11]
|
header.flags = imageInput.readInt(); // [8,11]
|
||||||
if (!header.hasFlag(DDS.FLAG_CAPS | DDS.FLAG_HEIGHT | DDS.FLAG_WIDTH | DDS.FLAG_PIXELFORMAT)) {
|
if (!header.getFlag(DDS.FLAG_CAPS
|
||||||
// NOTE: The Microsoft DDS documentation mention that readers should not rely on these flags...
|
| DDS.FLAG_HEIGHT
|
||||||
throw new IIOException("Required DDS flag missing in header: " + Integer.toBinaryString(header.flags));
|
| DDS.FLAG_WIDTH
|
||||||
|
| DDS.FLAG_PIXELFORMAT)) {
|
||||||
|
throw new IIOException("Required DDS Flag missing in header: " + Integer.toBinaryString(header.flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read Height & Width
|
// Read Height & Width
|
||||||
@@ -97,13 +93,11 @@ final class DDSHeader {
|
|||||||
// build dimensions list
|
// build dimensions list
|
||||||
header.addDimensions(dwWidth, dwHeight);
|
header.addDimensions(dwWidth, dwHeight);
|
||||||
|
|
||||||
imageInput.skipBytes(44);
|
byte[] dwReserved1 = new byte[11 * 4]; // [32,75]
|
||||||
|
imageInput.readFully(dwReserved1);
|
||||||
|
|
||||||
// DDS_PIXELFORMAT structure
|
// DDS_PIXELFORMAT structure
|
||||||
int px_dwSize = imageInput.readInt(); // [76,79]
|
int px_dwSize = imageInput.readInt(); // [76,79]
|
||||||
if (px_dwSize != DDS.PIXELFORMAT_SIZE) {
|
|
||||||
throw new IIOException(String.format("Invalid DDS pixel format structure size (expected %d): %d", DDS.PIXELFORMAT_SIZE, dwSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
header.pixelFormatFlags = imageInput.readInt(); // [80,83]
|
header.pixelFormatFlags = imageInput.readInt(); // [80,83]
|
||||||
header.fourCC = imageInput.readInt(); // [84,87]
|
header.fourCC = imageInput.readInt(); // [84,87]
|
||||||
@@ -120,11 +114,6 @@ final class DDSHeader {
|
|||||||
|
|
||||||
int dwReserved2 = imageInput.readInt(); // [124,127]
|
int dwReserved2 = imageInput.readInt(); // [124,127]
|
||||||
|
|
||||||
if (header.fourCC == DDSType.DXT10.fourCC()) {
|
|
||||||
// If DXT10, the DXT10 header will follow immediately
|
|
||||||
header.dxt10Header = DXT10Header.read(imageInput);
|
|
||||||
}
|
|
||||||
|
|
||||||
return header;
|
return header;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -140,8 +129,8 @@ final class DDSHeader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasFlag(int mask) {
|
private boolean getFlag(int mask) {
|
||||||
return (flags & mask) == mask;
|
return (flags & mask) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getWidth(int imageIndex) {
|
int getWidth(int imageIndex) {
|
||||||
@@ -158,101 +147,31 @@ final class DDSHeader {
|
|||||||
return mipMapCount;
|
return mipMapCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
DDSType getType() throws IIOException {
|
int getBitCount() {
|
||||||
if (dxt10Header != null) {
|
return bitCount;
|
||||||
return dxt10Header.getType();
|
|
||||||
}
|
|
||||||
|
|
||||||
return getRawType();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DDSType getRawType() throws IIOException {
|
int getFourCC() {
|
||||||
if ((pixelFormatFlags & DDS.PIXEL_FORMAT_FLAG_FOURCC) != 0) {
|
return fourCC;
|
||||||
// DXT
|
|
||||||
return DDSType.fromFourCC(fourCC);
|
|
||||||
}
|
|
||||||
else if ((pixelFormatFlags & DDS.PIXEL_FORMAT_FLAG_RGB) != 0) {
|
|
||||||
// RGB
|
|
||||||
int alphaMask = ((pixelFormatFlags & 0x01) != 0) ? this.alphaMask : 0; // 0x01 alpha
|
|
||||||
|
|
||||||
if (bitCount == 16) {
|
|
||||||
if (redMask == A1R5G5B5_MASKS[0] && greenMask == A1R5G5B5_MASKS[1] && blueMask == A1R5G5B5_MASKS[2] && alphaMask == A1R5G5B5_MASKS[3]) {
|
|
||||||
// A1R5G5B5
|
|
||||||
return DDSType.A1R5G5B5;
|
|
||||||
}
|
|
||||||
else if (redMask == X1R5G5B5_MASKS[0] && greenMask == X1R5G5B5_MASKS[1] && blueMask == X1R5G5B5_MASKS[2] && alphaMask == X1R5G5B5_MASKS[3]) {
|
|
||||||
// X1R5G5B5
|
|
||||||
return DDSType.X1R5G5B5;
|
|
||||||
}
|
|
||||||
else if (redMask == A4R4G4B4_MASKS[0] && greenMask == A4R4G4B4_MASKS[1] && blueMask == A4R4G4B4_MASKS[2] && alphaMask == A4R4G4B4_MASKS[3]) {
|
|
||||||
// A4R4G4B4
|
|
||||||
return DDSType.A4R4G4B4;
|
|
||||||
}
|
|
||||||
else if (redMask == X4R4G4B4_MASKS[0] && greenMask == X4R4G4B4_MASKS[1] && blueMask == X4R4G4B4_MASKS[2] && alphaMask == X4R4G4B4_MASKS[3]) {
|
|
||||||
// X4R4G4B4
|
|
||||||
return DDSType.X4R4G4B4;
|
|
||||||
}
|
|
||||||
else if (redMask == R5G6B5_MASKS[0] && greenMask == R5G6B5_MASKS[1] && blueMask == R5G6B5_MASKS[2] && alphaMask == R5G6B5_MASKS[3]) {
|
|
||||||
// R5G6B5
|
|
||||||
return DDSType.R5G6B5;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IIOException("Unsupported 16bit RGB image.");
|
|
||||||
}
|
|
||||||
else if (bitCount == 24) {
|
|
||||||
if (redMask == R8G8B8_MASKS[0] && greenMask == R8G8B8_MASKS[1] && blueMask == R8G8B8_MASKS[2] && alphaMask == R8G8B8_MASKS[3]) {
|
|
||||||
// R8G8B8
|
|
||||||
return DDSType.R8G8B8;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IIOException("Unsupported 24bit RGB image.");
|
|
||||||
}
|
|
||||||
else if (bitCount == 32) {
|
|
||||||
if (redMask == A8B8G8R8_MASKS[0] && greenMask == A8B8G8R8_MASKS[1] && blueMask == A8B8G8R8_MASKS[2] && alphaMask == A8B8G8R8_MASKS[3]) {
|
|
||||||
// A8B8G8R8
|
|
||||||
return DDSType.A8B8G8R8;
|
|
||||||
}
|
|
||||||
else if (redMask == X8B8G8R8_MASKS[0] && greenMask == X8B8G8R8_MASKS[1] && blueMask == X8B8G8R8_MASKS[2] && alphaMask == X8B8G8R8_MASKS[3]) {
|
|
||||||
// X8B8G8R8
|
|
||||||
return DDSType.X8B8G8R8;
|
|
||||||
}
|
|
||||||
else if (redMask == A8R8G8B8_MASKS[0] && greenMask == A8R8G8B8_MASKS[1] && blueMask == A8R8G8B8_MASKS[2] && alphaMask == A8R8G8B8_MASKS[3]) {
|
|
||||||
// A8R8G8B8
|
|
||||||
return DDSType.A8R8G8B8;
|
|
||||||
}
|
|
||||||
else if (redMask == X8R8G8B8_MASKS[0] && greenMask == X8R8G8B8_MASKS[1] && blueMask == X8R8G8B8_MASKS[2] && alphaMask == X8R8G8B8_MASKS[3]) {
|
|
||||||
// X8R8G8B8
|
|
||||||
return DDSType.X8R8G8B8;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IIOException("Unsupported 32bit RGB image.");
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IIOException("Unsupported bit count: " + bitCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IIOException("Unsupported YUV or LUMINANCE image.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
int getPixelFormatFlags() {
|
||||||
public String toString() {
|
return pixelFormatFlags;
|
||||||
return "DDSHeader{" +
|
|
||||||
"flags=" + Integer.toBinaryString(flags) +
|
|
||||||
", mipMapCount=" + mipMapCount +
|
|
||||||
", dimensions=" + Arrays.toString(Arrays.stream(dimensions)
|
|
||||||
.map(DDSHeader::dimensionToString)
|
|
||||||
.toArray(String[]::new)) +
|
|
||||||
", pixelFormatFlags=" + Integer.toBinaryString(pixelFormatFlags) +
|
|
||||||
", fourCC=" + fourCC +
|
|
||||||
", bitCount=" + bitCount +
|
|
||||||
", redMask=" + redMask +
|
|
||||||
", greenMask=" + greenMask +
|
|
||||||
", blueMask=" + blueMask +
|
|
||||||
", alphaMask=" + alphaMask +
|
|
||||||
'}';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String dimensionToString(Dimension dimension) {
|
int getRedMask() {
|
||||||
return String.format("%dx%d", dimension.width, dimension.height);
|
return redMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getGreenMask() {
|
||||||
|
return greenMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getBlueMask() {
|
||||||
|
return blueMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getAlphaMask() {
|
||||||
|
return alphaMask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-477
@@ -1,477 +0,0 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.dds;
|
|
||||||
|
|
||||||
import javax.imageio.stream.ImageOutputStream;
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.image.Raster;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import static com.twelvemonkeys.imageio.plugins.dds.DDSReader.ARGB_ORDER;
|
|
||||||
import static com.twelvemonkeys.imageio.plugins.dds.DDSReader.BIT5;
|
|
||||||
import static com.twelvemonkeys.imageio.plugins.dds.DDSReader.BIT6;
|
|
||||||
import static com.twelvemonkeys.imageio.plugins.dds.DDSReader.RGB_16_ORDER;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A designated class to encode image data to binary.
|
|
||||||
*
|
|
||||||
* @see <a href="https://www.ludicon.com/castano/blog/2009/03/gpu-dxt-decompression/">GPU DXT Decompression</a>.
|
|
||||||
* @see <a href="https://sv-journal.org/2014-1/06/en/index.php">TEXTURE COMPRESSION TECHNIQUES</a>.
|
|
||||||
* @see <a href="https://mrelusive.com/publications/papers/Real-Time-Dxt-Compression.pdf">Real-Time DXT Compression by J.M.P. van Waveren</a>
|
|
||||||
* @see <a href="https://registry.khronos.org/DataFormat/specs/1.4/dataformat.1.4.pdf">Khronos Data Format Specification v1.4 by Andrew Garrard</a>
|
|
||||||
*/
|
|
||||||
class DDSImageDataEncoder {
|
|
||||||
private DDSImageDataEncoder() {}
|
|
||||||
//A cap for alpha value for BC1 where if alpha value is smaller than this, the 4x4 block will enable alpha mode.
|
|
||||||
private static final int BC1_ALPHA_CAP = 124;
|
|
||||||
private static final int BC4_CHANNEL_RED = 0; //default for BC4.
|
|
||||||
private static final int BC4_CHANNEL_ALPHA = 3; //BC3 reuses algorithm from BC4 but uses alpha channelIndex for sampling.
|
|
||||||
private static final int BC4_CHANNEL_GREEN = 1; //same re-usage as BC3 but for green channel BC5 uses
|
|
||||||
|
|
||||||
static void writeImageData(ImageOutputStream imageOutput, Raster raster, BlockCompression compression) throws IOException {
|
|
||||||
// TODO: Support compression == null for uncompressed RGB(A/X) data?
|
|
||||||
|
|
||||||
switch (compression) {
|
|
||||||
case BC1:
|
|
||||||
new BlockCompressor1(false).encode(imageOutput, raster);
|
|
||||||
break;
|
|
||||||
case BC2:
|
|
||||||
new BlockCompressor2().encode(imageOutput, raster);
|
|
||||||
break;
|
|
||||||
case BC3:
|
|
||||||
new BlockCompressor3().encode(imageOutput, raster);
|
|
||||||
break;
|
|
||||||
case BC4:
|
|
||||||
new BlockCompressor4(BC4_CHANNEL_RED).encode(imageOutput, raster);
|
|
||||||
break;
|
|
||||||
case BC5:
|
|
||||||
new BlockCompressor5().encode(imageOutput, raster);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("DDS block compression is not supported yet: " + compression);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class BlockCompressor1 extends BlockCompressorBase {
|
|
||||||
private final boolean forceOpaque;
|
|
||||||
//color0,1 : space 565
|
|
||||||
//color2,3 : space 888
|
|
||||||
private final int[] palettes;
|
|
||||||
private final MutableColor[] color32s;
|
|
||||||
|
|
||||||
private BlockCompressor1(boolean forceOpaque) {
|
|
||||||
super();
|
|
||||||
this.forceOpaque = forceOpaque;
|
|
||||||
palettes = new int[4];
|
|
||||||
color32s = new MutableColor[16];
|
|
||||||
for (int i = 0; i < 16; i++) {
|
|
||||||
color32s[i] = new MutableColor();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//pack 32 bits of the colors to a single int value.
|
|
||||||
private static int color888ToInt(int r, int g, int b, int a) {
|
|
||||||
return (a << ARGB_ORDER.alphaShift) | (r << ARGB_ORDER.redShift) | (g << ARGB_ORDER.greenShift) | (b << ARGB_ORDER.blueShift);
|
|
||||||
}
|
|
||||||
|
|
||||||
void startEncodeBlock(ImageOutputStream imageOutput, int[] sampled) throws IOException {
|
|
||||||
boolean alphaMode = getBlockEndpoints(sampled, palettes);
|
|
||||||
imageOutput.writeShort((short) palettes[0]);
|
|
||||||
imageOutput.writeShort((short) palettes[1]);
|
|
||||||
//simulating color2,3
|
|
||||||
interpolate(alphaMode, palettes);
|
|
||||||
//indices encoding start.
|
|
||||||
int indices = encodeBlockIndices(alphaMode, sampled, palettes);
|
|
||||||
imageOutput.writeInt(indices);
|
|
||||||
}
|
|
||||||
|
|
||||||
//all palettes now in 8:8:8 space
|
|
||||||
int encodeBlockIndices(boolean alphaMode, int[] sampled, int[] palettes) {
|
|
||||||
int i = 0;
|
|
||||||
int colorPos = 0;
|
|
||||||
int indices = 0;
|
|
||||||
|
|
||||||
Color c0 = convertTo888(palettes[0]);
|
|
||||||
Color c1 = convertTo888(palettes[1]);
|
|
||||||
Color c2 = color888ToObject(palettes[2]);
|
|
||||||
Color c3 = color888ToObject(palettes[3]);
|
|
||||||
|
|
||||||
while (i < 64) {
|
|
||||||
Color c = setColorFor(colorPos, sampled[i++], sampled[i++], sampled[i++]);
|
|
||||||
byte index;
|
|
||||||
int a = sampled[i++];
|
|
||||||
if (alphaMode && isAlphaBelowCap(a)) {
|
|
||||||
index = 0b11;
|
|
||||||
} else {
|
|
||||||
double distance0 = calculateDistance(c, c0);
|
|
||||||
double distance1 = calculateDistance(c, c1);
|
|
||||||
double distance2 = calculateDistance(c, c2);
|
|
||||||
double distance3 = calculateDistance(c, c3);
|
|
||||||
index = getClosest(distance0, distance1, distance2, distance3);
|
|
||||||
}
|
|
||||||
indices |= (index << (colorPos * 2));
|
|
||||||
colorPos++;
|
|
||||||
}
|
|
||||||
return indices;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Color setColorFor(int index, int r, int g, int b) {
|
|
||||||
color32s[index].setColor(r, g, b);
|
|
||||||
return color32s[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
//color space 888
|
|
||||||
private static double calculateDistance(Color color1, Color color0) {
|
|
||||||
float r = Math.abs(color0.getRed() - color1.getRed());
|
|
||||||
float g = Math.abs(color0.getGreen() - color1.getGreen());
|
|
||||||
float b = Math.abs(color0.getBlue() - color1.getBlue());
|
|
||||||
return Math.sqrt(r * r + g * g + b * b);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static byte getClosest(double d0, double d1, double d2, double d3) {
|
|
||||||
double min = Math.min(d0, Math.min(d1, Math.min(d2, d3)));
|
|
||||||
if (min == d0) return 0b00;
|
|
||||||
if (min == d1) return 0b01;
|
|
||||||
if (min == d2) return 0b10;
|
|
||||||
return 0b11;
|
|
||||||
}
|
|
||||||
|
|
||||||
//this method, we work in 888 space
|
|
||||||
@SuppressWarnings("DuplicatedCode")
|
|
||||||
//just in case intellij warns for 'duplication'
|
|
||||||
void interpolate(boolean alphaMode, int[] palettes) {
|
|
||||||
Color rgb0 = convertTo888(palettes[0]);
|
|
||||||
Color rgb1 = convertTo888(palettes[1]);
|
|
||||||
int rgb2;
|
|
||||||
int rgb3;
|
|
||||||
if (alphaMode) {
|
|
||||||
//alpha mode
|
|
||||||
int r2 = (rgb0.getRed() + rgb1.getRed()) / 2;
|
|
||||||
int g2 = (rgb0.getGreen() + rgb1.getGreen()) / 2;
|
|
||||||
int b2 = (rgb0.getBlue() + rgb1.getBlue()) / 2;
|
|
||||||
rgb2 = color888ToInt(r2, g2, b2, 0xff);
|
|
||||||
rgb3 = 0;
|
|
||||||
} else {
|
|
||||||
//opaque mode
|
|
||||||
int r2 = (2 * rgb0.getRed() + rgb1.getRed()) / 3;
|
|
||||||
int g2 = (2 * rgb0.getGreen() + rgb1.getGreen()) / 3;
|
|
||||||
int b2 = (2 * rgb0.getBlue() + rgb1.getBlue()) / 3;
|
|
||||||
rgb2 = color888ToInt(r2, g2, b2, 0xff);
|
|
||||||
|
|
||||||
int r3 = (rgb0.getRed() + 2 * rgb1.getRed()) / 3;
|
|
||||||
int g3 = (rgb0.getGreen() + 2 * rgb1.getGreen()) / 3;
|
|
||||||
int b3 = (rgb0.getBlue() + 2 * rgb1.getBlue()) / 3;
|
|
||||||
rgb3 = color888ToInt(r3, g3, b3, 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
palettes[2] = rgb2;
|
|
||||||
palettes[3] = rgb3;
|
|
||||||
}
|
|
||||||
|
|
||||||
//this method, we work in 888 space, return color0&1 in 565 space
|
|
||||||
boolean getBlockEndpoints(int[] sampledColors, int[] paletteBuffer) {
|
|
||||||
if (sampledColors.length != 64)
|
|
||||||
throw new IllegalStateException("Unintended behaviour, expecting sampled colors of block to be 64, got " + sampledColors.length);
|
|
||||||
int minR = 0xff;
|
|
||||||
int minG = 0xff;
|
|
||||||
int minB = 0xff;
|
|
||||||
|
|
||||||
int maxR = 0;
|
|
||||||
int maxG = 0;
|
|
||||||
int maxB = 0;
|
|
||||||
|
|
||||||
boolean alphaMode = false;
|
|
||||||
int i = 0;
|
|
||||||
while (i < 64) {
|
|
||||||
int r = sampledColors[i++];
|
|
||||||
int g = sampledColors[i++];
|
|
||||||
int b = sampledColors[i++];
|
|
||||||
int a = sampledColors[i++];
|
|
||||||
if (!forceOpaque && isAlphaBelowCap(a)) {
|
|
||||||
alphaMode = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
minR = Math.min(minR, r);
|
|
||||||
minG = Math.min(minG, g);
|
|
||||||
minB = Math.min(minB, b);
|
|
||||||
|
|
||||||
maxR = Math.max(maxR, r);
|
|
||||||
maxG = Math.max(maxG, g);
|
|
||||||
maxB = Math.max(maxB, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
int color0 = convertTo565(maxR, maxG, maxB);
|
|
||||||
int color1 = convertTo565(minR, minG, minB);
|
|
||||||
if ((alphaMode && color0 > color1) || (!alphaMode && color0 < color1)) {
|
|
||||||
paletteBuffer[0] = color1;
|
|
||||||
paletteBuffer[1] = color0;
|
|
||||||
} else {
|
|
||||||
paletteBuffer[0] = color0;
|
|
||||||
paletteBuffer[1] = color1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return alphaMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Reference [3] Page 7
|
|
||||||
boolean getBlockEndpoints2(int[] sampled, int[] paletteBuffer) {
|
|
||||||
int maxDistance = -1;
|
|
||||||
boolean alphaMode = false;
|
|
||||||
for (int i = 0; i < 60; i += 4) {
|
|
||||||
for (int j = i + 4; j < 64; j += 4) {
|
|
||||||
if (!forceOpaque && isAlphaBelowCap(Math.min(sampled[i + 3], sampled[j + 3]))) {
|
|
||||||
alphaMode = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int distance = getColorDistance(sampled[i], sampled[i + 1], sampled[i + 2], sampled[j], sampled[j + 1], sampled[j + 2]);
|
|
||||||
if (distance > maxDistance) {
|
|
||||||
maxDistance = distance;
|
|
||||||
paletteBuffer[0] = convertTo565(sampled[i], sampled[i + 1], sampled[i + 2]);
|
|
||||||
paletteBuffer[1] = convertTo565(sampled[j], sampled[j + 1], sampled[j + 2]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((alphaMode && paletteBuffer[0] > paletteBuffer[1]) || (!alphaMode && paletteBuffer[1] > paletteBuffer[0])) {
|
|
||||||
int a = paletteBuffer[0];
|
|
||||||
paletteBuffer[0] = paletteBuffer[1];
|
|
||||||
paletteBuffer[1] = a;
|
|
||||||
}
|
|
||||||
return alphaMode;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int getColorDistance(int r1, int g1, int b1, int r2, int g2, int b2) {
|
|
||||||
int r3 = r1 - r2;
|
|
||||||
int g3 = g1 - g2;
|
|
||||||
int b3 = b1 - b2;
|
|
||||||
return r3 * r3 + g3 * g3 + b3 * b3;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static Color convertTo888(int c565) {
|
|
||||||
int r8 = BIT5[(c565 & 0xF800) >> 11];
|
|
||||||
int g8 = BIT6[(c565 & 0x07E0) >> 5];
|
|
||||||
int b8 = BIT5[(c565 & 0x001F)];
|
|
||||||
return new Color(r8, g8, b8, 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Color color888ToObject(int c888) {
|
|
||||||
return new Color(
|
|
||||||
(c888 & 0xFF0000) >> ARGB_ORDER.redShift,
|
|
||||||
(c888 & 0x00FF00) >> ARGB_ORDER.greenShift,
|
|
||||||
(c888 & 0x0000FF) >> ARGB_ORDER.blueShift,
|
|
||||||
(c888) >>> ARGB_ORDER.alphaShift
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class BlockCompressor2 extends BlockCompressor1 {
|
|
||||||
|
|
||||||
private BlockCompressor2() {
|
|
||||||
super(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void startEncodeBlock(ImageOutputStream imageOutput, int[] sampled) throws IOException {
|
|
||||||
//write 64 bit alpha first (4 bit alpha per pixel)
|
|
||||||
long alphaData = 0;
|
|
||||||
for (int i = 0; i < 16; i++) {
|
|
||||||
int alpha = sampled[i * 4 + 3] >> 4;
|
|
||||||
alphaData |= ((long) alpha) << (i * 4);
|
|
||||||
}
|
|
||||||
imageOutput.writeLong(alphaData);
|
|
||||||
|
|
||||||
super.startEncodeBlock(imageOutput, sampled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class BlockCompressor3 extends BlockCompressor1 {
|
|
||||||
private final BlockCompressor4 bc4;
|
|
||||||
|
|
||||||
private BlockCompressor3() {
|
|
||||||
super(true);
|
|
||||||
bc4 = new BlockCompressor4(BC4_CHANNEL_ALPHA);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void startEncodeBlock(ImageOutputStream imageOutput, int[] sampled) throws IOException {
|
|
||||||
bc4.startEncodeBlock(imageOutput, sampled);
|
|
||||||
super.startEncodeBlock(imageOutput, sampled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class BlockCompressor4 extends BlockCompressorBase {
|
|
||||||
private final int channelIndex;
|
|
||||||
private final int[] reds;
|
|
||||||
|
|
||||||
private BlockCompressor4(int channelIndex) {
|
|
||||||
super();
|
|
||||||
this.channelIndex = channelIndex;
|
|
||||||
this.reds = new int[8];
|
|
||||||
}
|
|
||||||
|
|
||||||
void startEncodeBlock(ImageOutputStream imageOutput, int[] samples) throws IOException {
|
|
||||||
getColorRange(samples, reds);
|
|
||||||
interpolate(reds);
|
|
||||||
long data = calculateIndices(samples, reds);
|
|
||||||
data |= (((long) (reds[1] & 0xff) << 8) | (reds[0] & 0xff));
|
|
||||||
imageOutput.writeLong(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 6 bytes MSB will be for indices, the LSB is for the 2 red endpoints,
|
|
||||||
// as we write to file in LE the bytes will be swapped back to the desired order
|
|
||||||
private long calculateIndices(int[] samples, int[] reds) {
|
|
||||||
long data = 0;
|
|
||||||
for (int i = 0; i < 16; i++) {
|
|
||||||
int index;
|
|
||||||
int rSample = samples[i * 4 + channelIndex];
|
|
||||||
index = getNearest(rSample, reds);
|
|
||||||
data |= ((long) index << (16 + i * 3));
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getNearest(int r, int[] reds) {
|
|
||||||
int nearest = 0;
|
|
||||||
int nearestValue = 255;
|
|
||||||
for (int i = 0; i < 8; i++) {
|
|
||||||
int v = Math.abs(r - reds[i]);
|
|
||||||
if (nearestValue > v) {
|
|
||||||
nearest = i;
|
|
||||||
nearestValue = v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nearest;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void interpolate(int[] reds) {
|
|
||||||
int r0 = reds[0];
|
|
||||||
int r1 = reds[1];
|
|
||||||
for (int i = 0; i < 8; i++) {
|
|
||||||
reds[i] = DDSReader.getDXT5Alpha(r0, r1, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//r0 > r1 : use 6 interpolated color values
|
|
||||||
//r0 <= r1 : use 4
|
|
||||||
private void getColorRange(int[] samples, int[] red01) {
|
|
||||||
int r0 = 0;
|
|
||||||
int r1 = 255;
|
|
||||||
for (int i = 0; i < 16; i++) {
|
|
||||||
int r = samples[i * 4 + channelIndex];
|
|
||||||
r0 = Math.max(r0, r);
|
|
||||||
r1 = Math.min(r1, r);
|
|
||||||
}
|
|
||||||
red01[0] = r0;
|
|
||||||
red01[1] = r1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class BlockCompressor5 extends BlockCompressorBase {
|
|
||||||
private final BlockCompressor4 bc4r;
|
|
||||||
private final BlockCompressor4 bc4g;
|
|
||||||
|
|
||||||
public BlockCompressor5() {
|
|
||||||
bc4r = new BlockCompressor4(BC4_CHANNEL_RED);
|
|
||||||
bc4g = new BlockCompressor4(BC4_CHANNEL_GREEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
void startEncodeBlock(ImageOutputStream imageOutput, int[] samples) throws IOException {
|
|
||||||
bc4r.startEncodeBlock(imageOutput, samples);
|
|
||||||
bc4g.startEncodeBlock(imageOutput, samples);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//https://rgbcolorpicker.com/565
|
|
||||||
//pack 32 bits color into a single 5:6:5 16bits value
|
|
||||||
static int convertTo565(int r8, int g8, int b8) {
|
|
||||||
int r5 = (r8 >> 3);
|
|
||||||
int g6 = (g8 >> 2);
|
|
||||||
int b5 = (b8 >> 3);
|
|
||||||
return color565ToInt(r5, g6, b5);
|
|
||||||
}
|
|
||||||
|
|
||||||
//pack 16 bits of the colors to a single int value.
|
|
||||||
private static int color565ToInt(int r5, int g6, int b5) {
|
|
||||||
return (r5 << RGB_16_ORDER.redShift) | (g6 << RGB_16_ORDER.greenShift) | (b5 << RGB_16_ORDER.blueShift);
|
|
||||||
}
|
|
||||||
|
|
||||||
private abstract static class BlockCompressorBase {
|
|
||||||
final int[] samples;
|
|
||||||
|
|
||||||
BlockCompressorBase() {
|
|
||||||
this.samples = new int[64];
|
|
||||||
}
|
|
||||||
|
|
||||||
//workaround for 24 dpi (no alpha) -> 32dpi (with alpha default to 0xff)
|
|
||||||
//as this mess the color0 & color1 up spectacularly bc alpha is not present in 24dpi
|
|
||||||
private static void adjustSampledBands(Raster raster, int[] samples) {
|
|
||||||
if (raster.getNumBands() == 4) return;
|
|
||||||
for (int i = 15; i >= 0; i--) {
|
|
||||||
int r24Index = i * 3;
|
|
||||||
int r32Index = i * 4;
|
|
||||||
samples[r32Index + 3] = 0xFF;
|
|
||||||
samples[r32Index + 2] = samples[r24Index + 2]; //b24 -> b32
|
|
||||||
samples[r32Index + 1] = samples[r24Index + 1]; //g24 -> g32
|
|
||||||
samples[r32Index] = samples[r24Index]; //r24 -> r32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void encode(ImageOutputStream imageOutput, Raster raster) throws IOException {
|
|
||||||
int blocksXCount = (raster.getWidth() + 3) / 4;
|
|
||||||
int blocksYCount = (raster.getHeight() + 3) / 4;
|
|
||||||
|
|
||||||
for (int blockY = 0; blockY < blocksYCount; blockY++) {
|
|
||||||
for (int blockX = 0; blockX < blocksXCount; blockX++) {
|
|
||||||
raster.getPixels(blockX * 4, blockY * 4, 4, 4, samples);
|
|
||||||
adjustSampledBands(raster, samples);
|
|
||||||
startEncodeBlock(imageOutput, samples);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isAlphaBelowCap(int alpha) {
|
|
||||||
return alpha < BC1_ALPHA_CAP;
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract void startEncodeBlock(ImageOutputStream imageOutput, int[] samples) throws IOException;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class MutableColor extends Color {
|
|
||||||
|
|
||||||
int mutableValue;
|
|
||||||
|
|
||||||
public MutableColor() {
|
|
||||||
super(0, 0, 0);
|
|
||||||
this.mutableValue = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setColor(int red, int green, int blue) {
|
|
||||||
mutableValue = red << ARGB_ORDER.redShift;
|
|
||||||
mutableValue |= green << ARGB_ORDER.greenShift;
|
|
||||||
mutableValue |= blue << ARGB_ORDER.blueShift;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getRGB() {
|
|
||||||
return this.mutableValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//intellij generated
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object object) {
|
|
||||||
if (!(object instanceof MutableColor)) return false;
|
|
||||||
if (!super.equals(object)) return false;
|
|
||||||
|
|
||||||
MutableColor that = (MutableColor) object;
|
|
||||||
return mutableValue == that.mutableValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
int result = super.hashCode();
|
|
||||||
result = 31 * result + mutableValue;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+7
-27
@@ -30,16 +30,18 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.dds;
|
package com.twelvemonkeys.imageio.plugins.dds;
|
||||||
|
|
||||||
|
import static com.twelvemonkeys.imageio.util.IIOUtil.subsampleRow;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.ImageReaderBase;
|
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||||
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import javax.imageio.ImageReadParam;
|
import javax.imageio.ImageReadParam;
|
||||||
import javax.imageio.ImageTypeSpecifier;
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
import javax.imageio.metadata.IIOMetadata;
|
import javax.imageio.metadata.IIOMetadata;
|
||||||
import javax.imageio.spi.ImageReaderSpi;
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
import java.awt.Rectangle;
|
|
||||||
|
import java.awt.*;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -47,14 +49,6 @@ import java.nio.ByteOrder;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
import static com.twelvemonkeys.imageio.util.IIOUtil.subsampleRow;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ImageReader implementation for Microsoft DirectDraw Surface (DDS) format.
|
|
||||||
*
|
|
||||||
* @author Paul Allen
|
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
|
||||||
*/
|
|
||||||
public final class DDSImageReader extends ImageReaderBase {
|
public final class DDSImageReader extends ImageReaderBase {
|
||||||
|
|
||||||
private DDSHeader header;
|
private DDSHeader header;
|
||||||
@@ -97,16 +91,7 @@ public final class DDSImageReader extends ImageReaderBase {
|
|||||||
checkBounds(imageIndex);
|
checkBounds(imageIndex);
|
||||||
readHeader();
|
readHeader();
|
||||||
|
|
||||||
DDSType type = header.getType();
|
// TODO: Implement for the specific formats...
|
||||||
if (!type.isBlockCompression() && type.rgbaMasks[3] == 0) {
|
|
||||||
return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: DXT1 can have 1 bit alpha, usually don't...
|
|
||||||
// DXT3/5 have alpha
|
|
||||||
// DXT2/4 ...?
|
|
||||||
|
|
||||||
|
|
||||||
return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB);
|
return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,19 +147,14 @@ public final class DDSImageReader extends ImageReaderBase {
|
|||||||
public IIOMetadata getImageMetadata(int imageIndex) throws IOException {
|
public IIOMetadata getImageMetadata(int imageIndex) throws IOException {
|
||||||
ImageTypeSpecifier imageType = getRawImageType(imageIndex);
|
ImageTypeSpecifier imageType = getRawImageType(imageIndex);
|
||||||
|
|
||||||
return new DDSImageMetadata(imageType, header.getType());
|
return new DDSMetadata(imageType, header);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readHeader() throws IOException {
|
private void readHeader() throws IOException {
|
||||||
if (header == null) {
|
if (header == null) {
|
||||||
imageInput.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
imageInput.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
|
||||||
int magic = imageInput.readInt();
|
|
||||||
if (magic != DDS.MAGIC) {
|
|
||||||
throw new IIOException(String.format("Not a DDS file. Expected DDS magic 0x%8x', read 0x%8x", DDS.MAGIC, magic));
|
|
||||||
}
|
|
||||||
|
|
||||||
header = DDSHeader.read(imageInput);
|
header = DDSHeader.read(imageInput);
|
||||||
|
|
||||||
imageInput.flushBefore(imageInput.getStreamPosition());
|
imageInput.flushBefore(imageInput.getStreamPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-8
@@ -35,7 +35,7 @@ import com.twelvemonkeys.imageio.spi.ImageReaderSpiBase;
|
|||||||
import javax.imageio.ImageReader;
|
import javax.imageio.ImageReader;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteOrder;
|
import java.util.Arrays;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
public final class DDSImageReaderSpi extends ImageReaderSpiBase {
|
public final class DDSImageReaderSpi extends ImageReaderSpiBase {
|
||||||
@@ -53,15 +53,13 @@ public final class DDSImageReaderSpi extends ImageReaderSpiBase {
|
|||||||
ImageInputStream stream = (ImageInputStream) source;
|
ImageInputStream stream = (ImageInputStream) source;
|
||||||
|
|
||||||
stream.mark();
|
stream.mark();
|
||||||
ByteOrder byteOrder = stream.getByteOrder();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
stream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
byte[] magic = new byte[DDS.MAGIC.length];
|
||||||
|
stream.readFully(magic);
|
||||||
|
|
||||||
return stream.readInt() == DDS.MAGIC;
|
return Arrays.equals(DDS.MAGIC, magic);
|
||||||
}
|
} finally {
|
||||||
finally {
|
|
||||||
stream.setByteOrder(byteOrder);
|
|
||||||
stream.reset();
|
stream.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,6 +71,6 @@ public final class DDSImageReaderSpi extends ImageReaderSpiBase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDescription(Locale locale) {
|
public String getDescription(Locale locale) {
|
||||||
return "DirectDraw Surface (DDS) Image Reader";
|
return "Direct DrawSurface (DDS) Image Reader";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-62
@@ -1,62 +0,0 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.dds;
|
|
||||||
|
|
||||||
import javax.imageio.ImageWriteParam;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public final class DDSImageWriteParam extends ImageWriteParam {
|
|
||||||
|
|
||||||
static final DDSType DEFAULT_TYPE = DDSType.DXT5;
|
|
||||||
private static final String[] COMPRESSION_TYPES = compressionTypes();
|
|
||||||
|
|
||||||
private static String[] compressionTypes() {
|
|
||||||
// TODO: Maybe hardcode subset of values that we actually support writing?
|
|
||||||
List<String> compressionTypes = Arrays.stream(DDSType.values())
|
|
||||||
.filter(DDSType::isBlockCompression)
|
|
||||||
.map(Enum::name)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
compressionTypes.add(0, "None");
|
|
||||||
|
|
||||||
return compressionTypes.toArray(new String[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean writeDXT10;
|
|
||||||
|
|
||||||
DDSImageWriteParam() {
|
|
||||||
canWriteCompressed = true;
|
|
||||||
compressionTypes = COMPRESSION_TYPES;
|
|
||||||
compressionType = DEFAULT_TYPE.name();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setWriteDX10() {
|
|
||||||
writeDXT10 = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearWriteDX10() {
|
|
||||||
writeDXT10 = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isWriteDXT10() {
|
|
||||||
return writeDXT10;
|
|
||||||
}
|
|
||||||
|
|
||||||
DDSType type() {
|
|
||||||
if (compressionType == null || compressionType.equals("None")) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return DDSType.valueOf(compressionType);
|
|
||||||
}
|
|
||||||
|
|
||||||
int getDxgiFormat() {
|
|
||||||
DDSType type = type();
|
|
||||||
|
|
||||||
if (type != null) {
|
|
||||||
return type.dxgiFormat();
|
|
||||||
}
|
|
||||||
|
|
||||||
return DXGI.DXGI_FORMAT_UNKNOWN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-330
@@ -1,330 +0,0 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.dds;
|
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.ImageWriterBase;
|
|
||||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
|
||||||
import com.twelvemonkeys.imageio.util.SequenceSupport;
|
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
|
||||||
import javax.imageio.IIOImage;
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import javax.imageio.ImageTypeSpecifier;
|
|
||||||
import javax.imageio.ImageWriteParam;
|
|
||||||
import javax.imageio.metadata.IIOMetadata;
|
|
||||||
import javax.imageio.spi.ImageWriterSpi;
|
|
||||||
import javax.imageio.stream.MemoryCacheImageOutputStream;
|
|
||||||
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.image.Raster;
|
|
||||||
import java.awt.image.RenderedImage;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.ByteOrder;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ImageWriter implementation for Microsoft DirectDraw Surface (DDS) format.
|
|
||||||
*
|
|
||||||
* @author KhanTypo
|
|
||||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
|
||||||
*/
|
|
||||||
class DDSImageWriter extends ImageWriterBase {
|
|
||||||
|
|
||||||
private final SequenceSupport mipmapSequence = new SequenceSupport();
|
|
||||||
|
|
||||||
private long headerStartPos;
|
|
||||||
private DDSType mipmapType;
|
|
||||||
private Dimension mipmapDimension;
|
|
||||||
|
|
||||||
protected DDSImageWriter(ImageWriterSpi provider) {
|
|
||||||
super(provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DDSImageWriteParam getDefaultWriteParam() {
|
|
||||||
return new DDSImageWriteParam();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void resetMembers() {
|
|
||||||
headerStartPos = 0;
|
|
||||||
mipmapSequence.reset();
|
|
||||||
mipmapType = null;
|
|
||||||
mipmapDimension = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canWriteRasters() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canWriteSequence() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void prepareWriteSequence(IIOMetadata streamMetadata) throws IOException {
|
|
||||||
assertOutput();
|
|
||||||
mipmapSequence.start();
|
|
||||||
|
|
||||||
imageOutput.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
|
||||||
imageOutput.writeInt(DDS.MAGIC);
|
|
||||||
imageOutput.flush();
|
|
||||||
|
|
||||||
headerStartPos = imageOutput.getStreamPosition();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void endWriteSequence() throws IOException {
|
|
||||||
int mipmapCount = mipmapSequence.end();
|
|
||||||
|
|
||||||
// Go back and update header
|
|
||||||
updateHeader(mipmapCount);
|
|
||||||
|
|
||||||
mipmapType = null;
|
|
||||||
mipmapDimension = null;
|
|
||||||
|
|
||||||
imageOutput.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(IIOMetadata streamMetadata, IIOImage image, ImageWriteParam param) throws IOException {
|
|
||||||
prepareWriteSequence(streamMetadata);
|
|
||||||
writeToSequence(image, param);
|
|
||||||
endWriteSequence();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeToSequence(IIOImage image, ImageWriteParam param) throws IOException {
|
|
||||||
int mipmapIndex = mipmapSequence.advance();
|
|
||||||
|
|
||||||
Raster raster = getRaster(image);
|
|
||||||
ensureImageChannels(raster);
|
|
||||||
ensureTextureDimension(raster);
|
|
||||||
mipmapDimension = new Dimension(raster.getWidth(), raster.getHeight());
|
|
||||||
|
|
||||||
DDSImageWriteParam ddsParam = param instanceof DDSImageWriteParam
|
|
||||||
? ((DDSImageWriteParam) param)
|
|
||||||
: IIOUtil.copyStandardParams(param, getDefaultWriteParam());
|
|
||||||
|
|
||||||
DDSType type = ddsParam.type();
|
|
||||||
if (mipmapType == null) {
|
|
||||||
mipmapType = type;
|
|
||||||
}
|
|
||||||
else if (type != mipmapType) {
|
|
||||||
processWarningOccurred(mipmapIndex, "All images in DDS mipmap must use same pixel format and compression");
|
|
||||||
}
|
|
||||||
if (mipmapType == null) {
|
|
||||||
throw new IIOException("Only compressed DDS using DXT1-5 or DXT10 with block compression is currently supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mipmapIndex == 0) {
|
|
||||||
writeHeader(raster.getWidth(), raster.getHeight(), mipmapType, ddsParam.isWriteDXT10());
|
|
||||||
if (ddsParam.isWriteDXT10()) {
|
|
||||||
writeDXT10Header(ddsParam.getDxgiFormat());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
processImageStarted(mipmapIndex);
|
|
||||||
processImageProgress(0f);
|
|
||||||
|
|
||||||
DDSImageDataEncoder.writeImageData(imageOutput, raster, mipmapType.compression);
|
|
||||||
|
|
||||||
processImageProgress(100f);
|
|
||||||
processImageComplete();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Raster getRaster(IIOImage image) throws IIOException {
|
|
||||||
if (image.hasRaster()) {
|
|
||||||
return image.getRaster();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
RenderedImage renderedImage = image.getRenderedImage();
|
|
||||||
|
|
||||||
if (renderedImage.getNumXTiles() != 1 || renderedImage.getNumYTiles() != 1) {
|
|
||||||
throw new IIOException("Only single tile images supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
return renderedImage.getTile(0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checking if the image has 3 channels (RGB) or 4 channels (RGBA) and if image has 8 bits/channel.
|
|
||||||
*
|
|
||||||
* @see DDSImageWriterSpi#canEncodeImage(ImageTypeSpecifier)
|
|
||||||
*/
|
|
||||||
private void ensureImageChannels(Raster data) throws IIOException {
|
|
||||||
int numBands = data.getNumBands();
|
|
||||||
if (numBands < 3 || numBands > 4) {
|
|
||||||
throw new IIOException(
|
|
||||||
"Only image with 3 channels (RGB) or 4 channels (RGBA) is supported, got " + numBands + " channels");
|
|
||||||
}
|
|
||||||
|
|
||||||
int sampleSize = data.getSampleModel().getSampleSize(0);
|
|
||||||
if (sampleSize != 8) {
|
|
||||||
throw new IIOException("Only image with 8 bits/channel is supported, got " + sampleSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checking if an image can be evenly divided into blocks of 4x4, ideally a power of 2.
|
|
||||||
* e.g. 16x16, 32x32, 512x128, 512x512, 1024x512, 1024x1024, 2048x1024...
|
|
||||||
*/
|
|
||||||
private void ensureTextureDimension(Raster raster) throws IIOException {
|
|
||||||
int width = raster.getWidth();
|
|
||||||
int height = raster.getHeight();
|
|
||||||
|
|
||||||
// Should also allow mipmaps 2x2 and 1x1?
|
|
||||||
if (width % 4 != 0 || height % 4 != 0) {
|
|
||||||
throw new IIOException(String.format("Image dimensions must be dividable by 4, ideally a power of 2; got %dx%d", width, height));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mipmapDimension != null && (mipmapDimension.width != width * 2|| mipmapDimension.height != height * 2)) {
|
|
||||||
throw new IIOException(
|
|
||||||
String.format("For mipmap, image dimensions must be exactly half of previous (%dx%d); got %dx%d",
|
|
||||||
mipmapDimension.width, mipmapDimension.height, width, height)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeHeader(int width, int height, DDSType type, boolean writeDXT10) throws IOException {
|
|
||||||
imageOutput.writeInt(DDS.HEADER_SIZE);
|
|
||||||
int linearSizeOrPitch = type.isBlockCompression() ? DDS.FLAG_LINEARSIZE : DDS.FLAG_PITCH;
|
|
||||||
imageOutput.writeInt(DDS.FLAG_CAPS | DDS.FLAG_HEIGHT | DDS.FLAG_WIDTH | DDS.FLAG_PIXELFORMAT | linearSizeOrPitch);
|
|
||||||
|
|
||||||
imageOutput.writeInt(height);
|
|
||||||
imageOutput.writeInt(width);
|
|
||||||
writePitchOrLinearSize(height, width, type);
|
|
||||||
//dwDepth
|
|
||||||
imageOutput.writeInt(0);
|
|
||||||
//dwMipmapCount
|
|
||||||
imageOutput.writeInt(1); // Should probably write 0 here for non-mipmap?
|
|
||||||
//reserved
|
|
||||||
imageOutput.write(new byte[44]);
|
|
||||||
//pixFmt
|
|
||||||
writePixelFormat(type, writeDXT10);
|
|
||||||
//dwCaps, right now we keep it simple by only using DDSCAP_TEXTURE as it is required.
|
|
||||||
imageOutput.writeInt(DDS.DDSCAPS_TEXTURE);
|
|
||||||
//dwCaps2, unused for now as we are not working with cube maps
|
|
||||||
imageOutput.writeInt(0);
|
|
||||||
//dwCaps3, dwCaps4, dwReserved2 : 3 unused integers
|
|
||||||
imageOutput.write(new byte[12]);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateHeader(int mipmapCount) throws IOException {
|
|
||||||
if (mipmapCount == 1) {
|
|
||||||
// Fast case, nothing to do
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
long streamPosition = imageOutput.getStreamPosition();
|
|
||||||
imageOutput.seek(headerStartPos + 4); // Seek back to header start, skip 4 byte header size
|
|
||||||
|
|
||||||
int flags = imageOutput.readInt();
|
|
||||||
imageOutput.seek(imageOutput.getStreamPosition() - 4);
|
|
||||||
imageOutput.writeInt(flags | DDS.FLAG_MIPMAPCOUNT);
|
|
||||||
|
|
||||||
imageOutput.seek(imageOutput.getStreamPosition() + 16);
|
|
||||||
imageOutput.writeInt(mipmapCount);
|
|
||||||
|
|
||||||
imageOutput.seek(streamPosition); // Restore pos
|
|
||||||
}
|
|
||||||
|
|
||||||
//https://learn.microsoft.com/en-us/windows/win32/direct3ddds/dds-pixelformat
|
|
||||||
private void writePixelFormat(DDSType type, boolean writeDXT10) throws IOException {
|
|
||||||
imageOutput.writeInt(DDS.PIXELFORMAT_SIZE);
|
|
||||||
writePixelFormatFlags(type, writeDXT10);
|
|
||||||
writeFourCC(type, writeDXT10);
|
|
||||||
writeRGBAData(type, writeDXT10);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeDXT10Header(int dxgiFormat) throws IOException {
|
|
||||||
//dxgiFormat
|
|
||||||
imageOutput.writeInt(dxgiFormat);
|
|
||||||
//resourceDimension
|
|
||||||
imageOutput.writeInt(DDS.D3D10_RESOURCE_DIMENSION_TEXTURE2D);
|
|
||||||
//miscFlag
|
|
||||||
imageOutput.writeInt(0);
|
|
||||||
//arraySize
|
|
||||||
imageOutput.writeInt(1);
|
|
||||||
//miscFlag2
|
|
||||||
imageOutput.writeInt(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeRGBAData(DDSType type, boolean writeDXT10) throws IOException {
|
|
||||||
if (!writeDXT10 && !type.isFourCC()) {
|
|
||||||
//dwRGBBitCount
|
|
||||||
imageOutput.writeInt(type.blockSize() * 8); // TODO: Is bitcount always a multiple of 8?
|
|
||||||
|
|
||||||
//dwRBitMask
|
|
||||||
imageOutput.writeInt(type.rgbaMasks[0]);
|
|
||||||
//dwGBitMask
|
|
||||||
imageOutput.writeInt(type.rgbaMasks[1]);
|
|
||||||
//dwBBitMask
|
|
||||||
imageOutput.writeInt(type.rgbaMasks[2]);
|
|
||||||
//dwABitMask
|
|
||||||
imageOutput.writeInt(type.rgbaMasks[3]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//write 5 zero integers as fourCC is used
|
|
||||||
imageOutput.write(new byte[20]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeFourCC(DDSType type, boolean writeDXT10) throws IOException {
|
|
||||||
if (writeDXT10) {
|
|
||||||
imageOutput.writeInt(DDSType.DXT10.fourCC());
|
|
||||||
}
|
|
||||||
else if (type.isFourCC()) {
|
|
||||||
imageOutput.writeInt(type.fourCC());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// No fourCC, custom format...
|
|
||||||
imageOutput.writeInt(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writePixelFormatFlags(DDSType type, boolean writeDXT10) throws IOException {
|
|
||||||
if (writeDXT10 || type.isFourCC()) {
|
|
||||||
imageOutput.writeInt(DDS.PIXEL_FORMAT_FLAG_FOURCC);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
imageOutput.writeInt(DDS.PIXEL_FORMAT_FLAG_RGB
|
|
||||||
| (type.rgbaMasks != null && type.rgbaMasks[3] != 0 ? DDS.PIXEL_FORMAT_FLAG_ALPHAPIXELS : 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writePitchOrLinearSize(int height, int width, DDSType type) throws IOException {
|
|
||||||
if (type.isBlockCompression()) {
|
|
||||||
imageOutput.writeInt(((width + 3) / 4) * ((height + 3) / 4) * type.blockSize());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
imageOutput.writeInt(width * type.blockSize());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageType, ImageWriteParam param) {
|
|
||||||
DDSType type = param instanceof DDSImageWriteParam
|
|
||||||
? ((DDSImageWriteParam) param).type()
|
|
||||||
: DDSImageWriteParam.DEFAULT_TYPE;
|
|
||||||
|
|
||||||
return new DDSImageMetadata(imageType, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IIOMetadata convertImageMetadata(IIOMetadata inData, ImageTypeSpecifier imageType, ImageWriteParam param) {
|
|
||||||
// Nothing useful to convert here...
|
|
||||||
return getDefaultImageMetadata(imageType, param);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) throws IOException {
|
|
||||||
if (args.length != 1) {
|
|
||||||
throw new IllegalArgumentException("Use 1 input file at a time.");
|
|
||||||
}
|
|
||||||
|
|
||||||
ImageIO.write(ImageIO.read(new File(args[0])), "dds", new MemoryCacheImageOutputStream(Files.newOutputStream(Paths.get("output.dds"))));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-34
@@ -1,34 +0,0 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.dds;
|
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.spi.ImageWriterSpiBase;
|
|
||||||
|
|
||||||
import javax.imageio.ImageTypeSpecifier;
|
|
||||||
import javax.imageio.ImageWriter;
|
|
||||||
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
public final class DDSImageWriterSpi extends ImageWriterSpiBase {
|
|
||||||
public DDSImageWriterSpi() {
|
|
||||||
super(new DDSProviderInfo());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canEncodeImage(ImageTypeSpecifier type) {
|
|
||||||
int numBands = type.getNumBands();
|
|
||||||
if (numBands < 3 || numBands > 4) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return type.getSampleModel().getSampleSize(0) == 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ImageWriter createWriterInstance(Object extension) {
|
|
||||||
return new DDSImageWriter(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDescription(Locale locale) {
|
|
||||||
return "DirectDraw Surface (DDS) Image Writer";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+14
-36
@@ -30,51 +30,29 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.dds;
|
package com.twelvemonkeys.imageio.plugins.dds;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.StandardImageMetadataSupport;
|
|
||||||
|
|
||||||
import javax.imageio.ImageTypeSpecifier;
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
|
|
||||||
final class DDSImageMetadata extends StandardImageMetadataSupport {
|
import com.twelvemonkeys.imageio.StandardImageMetadataSupport;
|
||||||
|
|
||||||
DDSImageMetadata(ImageTypeSpecifier specifier, DDSType type) {
|
final class DDSMetadata extends StandardImageMetadataSupport {
|
||||||
super(builder(specifier)
|
DDSMetadata(ImageTypeSpecifier type, DDSHeader header) {
|
||||||
.withCompressionTypeName(compressionName(type))
|
super(builder(type)
|
||||||
.withCompressionLossless(!type.isBlockCompression())
|
.withCompressionTypeName(compressionName(header))
|
||||||
.withBitsPerSample(bitsPerSample(type))
|
.withFormatVersion("1.0")
|
||||||
.withFormatVersion("1.0")
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String compressionName(DDSType type) {
|
private static String compressionName(DDSHeader header) {
|
||||||
if (type != null && type.isFourCC()) {
|
// If the fourCC is valid, compression is one of the DXTn versions, otherwise None
|
||||||
|
int flags = header.getPixelFormatFlags();
|
||||||
|
|
||||||
|
if ((flags & DDS.PIXEL_FORMAT_FLAG_FOURCC) != 0) {
|
||||||
|
// DXTn
|
||||||
|
DDSType type = DDSType.valueOf(header.getFourCC());
|
||||||
|
|
||||||
return type.name();
|
return type.name();
|
||||||
}
|
}
|
||||||
|
|
||||||
return "None";
|
return "None";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int[] bitsPerSample(DDSType type) {
|
|
||||||
if (type.isBlockCompression()) {
|
|
||||||
return null; // Use defaults
|
|
||||||
}
|
|
||||||
|
|
||||||
int[] bitsPerSample = new int[4];
|
|
||||||
|
|
||||||
for (int i = 0; i < bitsPerSample.length; i++) {
|
|
||||||
bitsPerSample[i] = countMaskBits(type.rgbaMasks[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return bitsPerSample;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int countMaskBits(int mask) {
|
|
||||||
// See https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
|
|
||||||
int count;
|
|
||||||
|
|
||||||
for (count = 0; mask != 0; count++) {
|
|
||||||
mask &= mask - 1; // clear the least significant bit set
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+10
-10
@@ -35,16 +35,16 @@ import com.twelvemonkeys.imageio.spi.ReaderWriterProviderInfo;
|
|||||||
final class DDSProviderInfo extends ReaderWriterProviderInfo {
|
final class DDSProviderInfo extends ReaderWriterProviderInfo {
|
||||||
DDSProviderInfo() {
|
DDSProviderInfo() {
|
||||||
super(
|
super(
|
||||||
DDSProviderInfo.class,
|
DDSProviderInfo.class,
|
||||||
new String[] { "DDS", "dds" },
|
new String[]{"DDS", "dds"},
|
||||||
new String[] { "dds" },
|
new String[]{"dds"},
|
||||||
new String[] { "image/vnd-ms.dds" },
|
new String[]{"image/vnd-ms.dds"},
|
||||||
"com.twelvemonkeys.imageio.plugins.dds.DDSImageReader",
|
"com.twelvemonkeys.imageio.plugins.dds.DDSImageReader",
|
||||||
new String[] { "com.twelvemonkeys.imageio.plugins.dds.DDSImageReaderSpi" },
|
new String[]{"com.twelvemonkeys.imageio.plugins.dds.DDSImageReaderSpi"},
|
||||||
"com.twelvemonkeys.imageio.plugins.dds.DDSImageWriter",
|
null,
|
||||||
new String[] { "com.twelvemonkeys.imageio.plugins.dds.DDSImageWriterSpi" },
|
null,
|
||||||
false, null, null, null, null,
|
false, null, null, null, null,
|
||||||
true, null, null, null, null
|
true, null, null, null, null
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+98
-38
@@ -70,8 +70,8 @@ import java.io.IOException;
|
|||||||
* <a href="http://3dtech.jp/wiki/index.php?DDSReader">Japanese document</a>
|
* <a href="http://3dtech.jp/wiki/index.php?DDSReader">Japanese document</a>
|
||||||
*/
|
*/
|
||||||
final class DDSReader {
|
final class DDSReader {
|
||||||
static final Order ARGB_ORDER = new Order(16, 8, 0, 24); // 8 alpha | 8 red | 8 green | 8 blue
|
|
||||||
static final Order RGB_16_ORDER = new Order(11, 5, 0, -1); // no alpha | 5 red | 6 green | 5 blue
|
static final Order ARGB_ORDER = new Order(16, 8, 0, 24);
|
||||||
|
|
||||||
private final DDSHeader header;
|
private final DDSHeader header;
|
||||||
|
|
||||||
@@ -80,21 +80,16 @@ final class DDSReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int[] read(ImageInputStream imageInput, int imageIndex) throws IOException {
|
int[] read(ImageInputStream imageInput, int imageIndex) throws IOException {
|
||||||
|
|
||||||
// type
|
// type
|
||||||
DDSType type = header.getType();
|
DDSType type = getType();
|
||||||
|
|
||||||
// offset buffer to index mipmap image
|
// offset buffer to index mipmap image
|
||||||
byte[] buffer = null;
|
byte[] buffer = null;
|
||||||
for (int i = 0; i <= imageIndex; i++) {
|
for (int i = 0; i <= imageIndex; i++) {
|
||||||
int len = getBufferLength(type, i);
|
int len = getLength(type, i);
|
||||||
|
buffer = new byte[len];
|
||||||
if (i == imageIndex) {
|
imageInput.readFully(buffer);
|
||||||
buffer = new byte[len];
|
|
||||||
imageInput.readFully(buffer);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
imageInput.seek(imageInput.getStreamPosition() + len);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int width = header.getWidth(imageIndex);
|
int width = header.getWidth(imageIndex);
|
||||||
@@ -136,17 +131,83 @@ final class DDSReader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getBufferLength(DDSType type, int imageIndex) throws IIOException {
|
private DDSType getType() throws IIOException {
|
||||||
|
int flags = header.getPixelFormatFlags();
|
||||||
|
|
||||||
|
if ((flags & DDS.PIXEL_FORMAT_FLAG_FOURCC) != 0) {
|
||||||
|
// DXT
|
||||||
|
int type = header.getFourCC();
|
||||||
|
return DDSType.valueOf(type);
|
||||||
|
|
||||||
|
} else if ((flags & DDS.PIXEL_FORMAT_FLAG_RGB) != 0) {
|
||||||
|
// RGB
|
||||||
|
int bitCount = header.getBitCount();
|
||||||
|
int redMask = header.getRedMask();
|
||||||
|
int greenMask = header.getGreenMask();
|
||||||
|
int blueMask = header.getBlueMask();
|
||||||
|
int alphaMask = ((flags & 0x01) != 0) ? header.getAlphaMask() : 0; // 0x01 alpha
|
||||||
|
if (bitCount == 16) {
|
||||||
|
if (redMask == A1R5G5B5_MASKS[0] && greenMask == A1R5G5B5_MASKS[1] && blueMask == A1R5G5B5_MASKS[2] && alphaMask == A1R5G5B5_MASKS[3]) {
|
||||||
|
// A1R5G5B5
|
||||||
|
return DDSType.A1R5G5B5;
|
||||||
|
} else if (redMask == X1R5G5B5_MASKS[0] && greenMask == X1R5G5B5_MASKS[1] && blueMask == X1R5G5B5_MASKS[2] && alphaMask == X1R5G5B5_MASKS[3]) {
|
||||||
|
// X1R5G5B5
|
||||||
|
return DDSType.X1R5G5B5;
|
||||||
|
} else if (redMask == A4R4G4B4_MASKS[0] && greenMask == A4R4G4B4_MASKS[1] && blueMask == A4R4G4B4_MASKS[2] && alphaMask == A4R4G4B4_MASKS[3]) {
|
||||||
|
// A4R4G4B4
|
||||||
|
return DDSType.A4R4G4B4;
|
||||||
|
} else if (redMask == X4R4G4B4_MASKS[0] && greenMask == X4R4G4B4_MASKS[1] && blueMask == X4R4G4B4_MASKS[2] && alphaMask == X4R4G4B4_MASKS[3]) {
|
||||||
|
// X4R4G4B4
|
||||||
|
return DDSType.X4R4G4B4;
|
||||||
|
} else if (redMask == R5G6B5_MASKS[0] && greenMask == R5G6B5_MASKS[1] && blueMask == R5G6B5_MASKS[2] && alphaMask == R5G6B5_MASKS[3]) {
|
||||||
|
// R5G6B5
|
||||||
|
return DDSType.R5G6B5;
|
||||||
|
} else {
|
||||||
|
throw new IIOException("Unsupported 16bit RGB image.");
|
||||||
|
}
|
||||||
|
} else if (bitCount == 24) {
|
||||||
|
if (redMask == R8G8B8_MASKS[0] && greenMask == R8G8B8_MASKS[1] && blueMask == R8G8B8_MASKS[2] && alphaMask == R8G8B8_MASKS[3]) {
|
||||||
|
// R8G8B8
|
||||||
|
return DDSType.R8G8B8;
|
||||||
|
} else {
|
||||||
|
throw new IIOException("Unsupported 24bit RGB image.");
|
||||||
|
}
|
||||||
|
} else if (bitCount == 32) {
|
||||||
|
if (redMask == A8B8G8R8_MASKS[0] && greenMask == A8B8G8R8_MASKS[1] && blueMask == A8B8G8R8_MASKS[2] && alphaMask == A8B8G8R8_MASKS[3]) {
|
||||||
|
// A8B8G8R8
|
||||||
|
return DDSType.A8B8G8R8;
|
||||||
|
} else if (redMask == X8B8G8R8_MASKS[0] && greenMask == X8B8G8R8_MASKS[1] && blueMask == X8B8G8R8_MASKS[2] && alphaMask == X8B8G8R8_MASKS[3]) {
|
||||||
|
// X8B8G8R8
|
||||||
|
return DDSType.X8B8G8R8;
|
||||||
|
} else if (redMask == A8R8G8B8_MASKS[0] && greenMask == A8R8G8B8_MASKS[1] && blueMask == A8R8G8B8_MASKS[2] && alphaMask == A8R8G8B8_MASKS[3]) {
|
||||||
|
// A8R8G8B8
|
||||||
|
return DDSType.A8R8G8B8;
|
||||||
|
} else if (redMask == X8R8G8B8_MASKS[0] && greenMask == X8R8G8B8_MASKS[1] && blueMask == X8R8G8B8_MASKS[2] && alphaMask == X8R8G8B8_MASKS[3]) {
|
||||||
|
// X8R8G8B8
|
||||||
|
return DDSType.X8R8G8B8;
|
||||||
|
} else {
|
||||||
|
throw new IIOException("Unsupported 32bit RGB image.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new IIOException("Unsupported bit count: " + bitCount);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new IIOException("Unsupported YUV or LUMINANCE image.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getLength(DDSType type, int imageIndex) throws IIOException {
|
||||||
int width = header.getWidth(imageIndex);
|
int width = header.getWidth(imageIndex);
|
||||||
int height = header.getHeight(imageIndex);
|
int height = header.getHeight(imageIndex);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case DXT1:
|
case DXT1:
|
||||||
|
return 8 * ((width + 3) / 4) * ((height + 3) / 4);
|
||||||
case DXT2:
|
case DXT2:
|
||||||
case DXT3:
|
case DXT3:
|
||||||
case DXT4:
|
case DXT4:
|
||||||
case DXT5:
|
case DXT5:
|
||||||
return type.blockSize() * ((width + 3) / 4) * ((height + 3) / 4);
|
return 16 * ((width + 3) / 4) * ((height + 3) / 4);
|
||||||
case A1R5G5B5:
|
case A1R5G5B5:
|
||||||
case X1R5G5B5:
|
case X1R5G5B5:
|
||||||
case A4R4G4B4:
|
case A4R4G4B4:
|
||||||
@@ -157,13 +218,12 @@ final class DDSReader {
|
|||||||
case X8B8G8R8:
|
case X8B8G8R8:
|
||||||
case A8R8G8B8:
|
case A8R8G8B8:
|
||||||
case X8R8G8B8:
|
case X8R8G8B8:
|
||||||
return type.blockSize() * width * height;
|
return (type.value() & 0xFF) * width * height;
|
||||||
default:
|
default:
|
||||||
throw new IIOException("Unknown type: " + type);
|
throw new IIOException("Unknown type: " + Integer.toHexString(type.value()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static int[] decodeDXT1(int width, int height, byte[] buffer) {
|
private static int[] decodeDXT1(int width, int height, byte[] buffer) {
|
||||||
int[] pixels = new int[width * height];
|
int[] pixels = new int[width * height];
|
||||||
int index = 0;
|
int index = 0;
|
||||||
@@ -181,7 +241,7 @@ final class DDSReader {
|
|||||||
int t1 = (buffer[index] & 0x0C) >> 2;
|
int t1 = (buffer[index] & 0x0C) >> 2;
|
||||||
int t2 = (buffer[index] & 0x30) >> 4;
|
int t2 = (buffer[index] & 0x30) >> 4;
|
||||||
int t3 = (buffer[index++] & 0xC0) >> 6;
|
int t3 = (buffer[index++] & 0xC0) >> 6;
|
||||||
pixels[4 * width * i + 4 * j + width * k] = getDXTColor(c0, c1, 0xFF, t0);
|
pixels[4 * width * i + 4 * j + width * k ] = getDXTColor(c0, c1, 0xFF, t0);
|
||||||
if (4 * j + 1 >= width) continue;
|
if (4 * j + 1 >= width) continue;
|
||||||
pixels[4 * width * i + 4 * j + width * k + 1] = getDXTColor(c0, c1, 0xFF, t1);
|
pixels[4 * width * i + 4 * j + width * k + 1] = getDXTColor(c0, c1, 0xFF, t1);
|
||||||
if (4 * j + 2 >= width) continue;
|
if (4 * j + 2 >= width) continue;
|
||||||
@@ -226,7 +286,7 @@ final class DDSReader {
|
|||||||
int t1 = (buffer[index] & 0x0C) >> 2;
|
int t1 = (buffer[index] & 0x0C) >> 2;
|
||||||
int t2 = (buffer[index] & 0x30) >> 4;
|
int t2 = (buffer[index] & 0x30) >> 4;
|
||||||
int t3 = (buffer[index++] & 0xC0) >> 6;
|
int t3 = (buffer[index++] & 0xC0) >> 6;
|
||||||
pixels[4 * width * i + 4 * j + width * k] = getDXTColor(c0, c1, alphaTable[4 * k], t0);
|
pixels[4 * width * i + 4 * j + width * k ] = getDXTColor(c0, c1, alphaTable[4 * k ], t0);
|
||||||
if (4 * j + 1 >= width) continue;
|
if (4 * j + 1 >= width) continue;
|
||||||
pixels[4 * width * i + 4 * j + width * k + 1] = getDXTColor(c0, c1, alphaTable[4 * k + 1], t1);
|
pixels[4 * width * i + 4 * j + width * k + 1] = getDXTColor(c0, c1, alphaTable[4 * k + 1], t1);
|
||||||
if (4 * j + 2 >= width) continue;
|
if (4 * j + 2 >= width) continue;
|
||||||
@@ -284,7 +344,7 @@ final class DDSReader {
|
|||||||
int t1 = (buffer[index] & 0x0C) >> 2;
|
int t1 = (buffer[index] & 0x0C) >> 2;
|
||||||
int t2 = (buffer[index] & 0x30) >> 4;
|
int t2 = (buffer[index] & 0x30) >> 4;
|
||||||
int t3 = (buffer[index++] & 0xC0) >> 6;
|
int t3 = (buffer[index++] & 0xC0) >> 6;
|
||||||
pixels[4 * width * i + 4 * j + width * k] = getDXTColor(c0, c1, getDXT5Alpha(a0, a1, alphaTable[4 * k]), t0);
|
pixels[4 * width * i + 4 * j + width * k ] = getDXTColor(c0, c1, getDXT5Alpha(a0, a1, alphaTable[4 * k ]), t0);
|
||||||
if (4 * j + 1 >= width) continue;
|
if (4 * j + 1 >= width) continue;
|
||||||
pixels[4 * width * i + 4 * j + width * k + 1] = getDXTColor(c0, c1, getDXT5Alpha(a0, a1, alphaTable[4 * k + 1]), t1);
|
pixels[4 * width * i + 4 * j + width * k + 1] = getDXTColor(c0, c1, getDXT5Alpha(a0, a1, alphaTable[4 * k + 1]), t1);
|
||||||
if (4 * j + 2 >= width) continue;
|
if (4 * j + 2 >= width) continue;
|
||||||
@@ -439,7 +499,7 @@ final class DDSReader {
|
|||||||
return pixels;
|
return pixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getDXTColor(int c0, int c1, int a, int t) {
|
private static int getDXTColor(int c0, int c1, int a, int t) {
|
||||||
switch (t) {
|
switch (t) {
|
||||||
case 0:
|
case 0:
|
||||||
return getDXTColor1(c0, a);
|
return getDXTColor1(c0, a);
|
||||||
@@ -455,7 +515,7 @@ final class DDSReader {
|
|||||||
|
|
||||||
private static int getDXTColor2_1(int c0, int c1, int a) {
|
private static int getDXTColor2_1(int c0, int c1, int a) {
|
||||||
// 2*c0/3 + c1/3
|
// 2*c0/3 + c1/3
|
||||||
int r = (2 * BIT5[(c0 & 0xF800) >> 11] + BIT5[(c1 & 0xF800) >> 11]) / 3;
|
int r = (2 * BIT5[(c0 & 0xFC00) >> 11] + BIT5[(c1 & 0xFC00) >> 11]) / 3;
|
||||||
int g = (2 * BIT6[(c0 & 0x07E0) >> 5] + BIT6[(c1 & 0x07E0) >> 5]) / 3;
|
int g = (2 * BIT6[(c0 & 0x07E0) >> 5] + BIT6[(c1 & 0x07E0) >> 5]) / 3;
|
||||||
int b = (2 * BIT5[c0 & 0x001F] + BIT5[c1 & 0x001F]) / 3;
|
int b = (2 * BIT5[c0 & 0x001F] + BIT5[c1 & 0x001F]) / 3;
|
||||||
return (a << ARGB_ORDER.alphaShift) | (r << ARGB_ORDER.redShift) | (g << ARGB_ORDER.greenShift) | (b << ARGB_ORDER.blueShift);
|
return (a << ARGB_ORDER.alphaShift) | (r << ARGB_ORDER.redShift) | (g << ARGB_ORDER.greenShift) | (b << ARGB_ORDER.blueShift);
|
||||||
@@ -463,20 +523,20 @@ final class DDSReader {
|
|||||||
|
|
||||||
private static int getDXTColor1_1(int c0, int c1, int a) {
|
private static int getDXTColor1_1(int c0, int c1, int a) {
|
||||||
// (c0+c1) / 2
|
// (c0+c1) / 2
|
||||||
int r = (BIT5[(c0 & 0xF800) >> 11] + BIT5[(c1 & 0xF800) >> 11]) / 2;
|
int r = (BIT5[(c0 & 0xFC00) >> 11] + BIT5[(c1 & 0xFC00) >> 11]) / 2;
|
||||||
int g = (BIT6[(c0 & 0x07E0) >> 5] + BIT6[(c1 & 0x07E0) >> 5]) / 2;
|
int g = (BIT6[(c0 & 0x07E0) >> 5] + BIT6[(c1 & 0x07E0) >> 5]) / 2;
|
||||||
int b = (BIT5[c0 & 0x001F] + BIT5[c1 & 0x001F]) / 2;
|
int b = (BIT5[c0 & 0x001F] + BIT5[c1 & 0x001F]) / 2;
|
||||||
return (a << ARGB_ORDER.alphaShift) | (r << ARGB_ORDER.redShift) | (g << ARGB_ORDER.greenShift) | (b << ARGB_ORDER.blueShift);
|
return (a << ARGB_ORDER.alphaShift) | (r << ARGB_ORDER.redShift) | (g << ARGB_ORDER.greenShift) | (b << ARGB_ORDER.blueShift);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getDXTColor1(int c, int a) {
|
private static int getDXTColor1(int c, int a) {
|
||||||
int r = BIT5[(c & 0xF800) >> 11];
|
int r = BIT5[(c & 0xFC00) >> 11];
|
||||||
int g = BIT6[(c & 0x07E0) >> 5];
|
int g = BIT6[(c & 0x07E0) >> 5];
|
||||||
int b = BIT5[(c & 0x001F)];
|
int b = BIT5[(c & 0x001F)];
|
||||||
return (a << ARGB_ORDER.alphaShift) | (r << ARGB_ORDER.redShift) | (g << ARGB_ORDER.greenShift) | (b << ARGB_ORDER.blueShift);
|
return (a << ARGB_ORDER.alphaShift) | (r << ARGB_ORDER.redShift) | (g << ARGB_ORDER.greenShift) | (b << ARGB_ORDER.blueShift);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getDXT5Alpha(int a0, int a1, int t) {
|
private static int getDXT5Alpha(int a0, int a1, int t) {
|
||||||
if (a0 > a1) switch (t) {
|
if (a0 > a1) switch (t) {
|
||||||
case 0:
|
case 0:
|
||||||
return a0;
|
return a0;
|
||||||
@@ -517,22 +577,22 @@ final class DDSReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RGBA Masks
|
// RGBA Masks
|
||||||
static final int[] A1R5G5B5_MASKS = {0x7C00, 0x03E0, 0x001F, 0x8000};
|
private static final int[] A1R5G5B5_MASKS = {0x7C00, 0x03E0, 0x001F, 0x8000};
|
||||||
static final int[] X1R5G5B5_MASKS = {0x7C00, 0x03E0, 0x001F, 0x0000};
|
private static final int[] X1R5G5B5_MASKS = {0x7C00, 0x03E0, 0x001F, 0x0000};
|
||||||
static final int[] A4R4G4B4_MASKS = {0x0F00, 0x00F0, 0x000F, 0xF000};
|
private static final int[] A4R4G4B4_MASKS = {0x0F00, 0x00F0, 0x000F, 0xF000};
|
||||||
static final int[] X4R4G4B4_MASKS = {0x0F00, 0x00F0, 0x000F, 0x0000};
|
private static final int[] X4R4G4B4_MASKS = {0x0F00, 0x00F0, 0x000F, 0x0000};
|
||||||
static final int[] R5G6B5_MASKS = {0xF800, 0x07E0, 0x001F, 0x0000};
|
private static final int[] R5G6B5_MASKS = {0xF800, 0x07E0, 0x001F, 0x0000};
|
||||||
static final int[] R8G8B8_MASKS = {0xFF0000, 0x00FF00, 0x0000FF, 0x000000};
|
private static final int[] R8G8B8_MASKS = {0xFF0000, 0x00FF00, 0x0000FF, 0x000000};
|
||||||
static final int[] A8B8G8R8_MASKS = {0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000};
|
private static final int[] A8B8G8R8_MASKS = {0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000};
|
||||||
static final int[] X8B8G8R8_MASKS = {0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000};
|
private static final int[] X8B8G8R8_MASKS = {0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000};
|
||||||
static final int[] A8R8G8B8_MASKS = {0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000};
|
private static final int[] A8R8G8B8_MASKS = {0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000};
|
||||||
static final int[] X8R8G8B8_MASKS = {0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000};
|
private static final int[] X8R8G8B8_MASKS = {0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000};
|
||||||
|
|
||||||
// BIT4 = 17 * index;
|
// BIT4 = 17 * index;
|
||||||
static final int[] BIT5 = {0, 8, 16, 25, 33, 41, 49, 58, 66, 74, 82, 90, 99, 107, 115, 123, 132, 140, 148, 156, 165, 173, 181, 189, 197, 206, 214, 222, 230, 239, 247, 255};
|
private static final int[] BIT5 = {0, 8, 16, 25, 33, 41, 49, 58, 66, 74, 82, 90, 99, 107, 115, 123, 132, 140, 148, 156, 165, 173, 181, 189, 197, 206, 214, 222, 230, 239, 247, 255};
|
||||||
static final int[] BIT6 = {0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 130, 134, 138, 142, 146, 150, 154, 158, 162, 166, 170, 174, 178, 182, 186, 190, 194, 198, 202, 206, 210, 215, 219, 223, 227, 231, 235, 239, 243, 247, 251, 255};
|
private static final int[] BIT6 = {0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 45, 49, 53, 57, 61, 65, 69, 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 130, 134, 138, 142, 146, 150, 154, 158, 162, 166, 170, 174, 178, 182, 186, 190, 194, 198, 202, 206, 210, 215, 219, 223, 227, 231, 235, 239, 243, 247, 251, 255};
|
||||||
|
|
||||||
static final class Order {
|
private static final class Order {
|
||||||
Order(int redShift, int greenShift, int blueShift, int alphaShift) {
|
Order(int redShift, int greenShift, int blueShift, int alphaShift) {
|
||||||
this.redShift = redShift;
|
this.redShift = redShift;
|
||||||
this.greenShift = greenShift;
|
this.greenShift = greenShift;
|
||||||
|
|||||||
+25
-140
@@ -30,156 +30,41 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.dds;
|
package com.twelvemonkeys.imageio.plugins.dds;
|
||||||
|
|
||||||
import static com.twelvemonkeys.imageio.plugins.dds.BlockCompression.*;
|
|
||||||
import static com.twelvemonkeys.imageio.plugins.dds.DDSReader.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <a href="https://learn.microsoft.com/en-us/windows/win32/direct3d10/d3d10-graphics-programming-guide-resources-block-compression#compression-algorithms">Compression Algorithms</a>
|
|
||||||
* <a href="https://github.com/microsoft/DirectXTK12/wiki/DDSTextureLoader#remarks">An extended Non-DX10 FourCC list</a>
|
|
||||||
*/
|
|
||||||
enum DDSType {
|
enum DDSType {
|
||||||
// Compressed types
|
|
||||||
DXT1('D' + ('X' << 8) + ('T' << 16) + ('1' << 24), 8, DXGI.DXGI_FORMAT_BC1_UNORM, BC1),
|
|
||||||
DXT2('D' + ('X' << 8) + ('T' << 16) + ('2' << 24), 16, DXGI.DXGI_FORMAT_BC2_UNORM, BC2),
|
|
||||||
DXT3('D' + ('X' << 8) + ('T' << 16) + ('3' << 24), 16, DXGI.DXGI_FORMAT_BC2_UNORM, BC2),
|
|
||||||
DXT4('D' + ('X' << 8) + ('T' << 16) + ('4' << 24), 16, DXGI.DXGI_FORMAT_BC3_UNORM, BC3),
|
|
||||||
DXT5('D' + ('X' << 8) + ('T' << 16) + ('5' << 24), 16, DXGI.DXGI_FORMAT_BC3_UNORM, BC3),
|
|
||||||
|
|
||||||
ATI1('A' + ('T' << 8) + ('I' << 16) + ('1' << 24), 8, DXGI.DXGI_FORMAT_BC4_UNORM, BC4), // AKA BC4U
|
DXT1(0x31545844),
|
||||||
BC4U('B' + ('C' << 8) + ('4' << 16) + ('U' << 24), 8, DXGI.DXGI_FORMAT_BC4_UNORM, BC4),
|
DXT2(0x32545844),
|
||||||
BC4S('B' + ('C' << 8) + ('4' << 16) + ('S' << 24), 8, DXGI.DXGI_FORMAT_BC4_SNORM, BC4),
|
DXT3(0x33545844),
|
||||||
ATI2('A' + ('T' << 8) + ('I' << 16) + ('2' << 24), 16, DXGI.DXGI_FORMAT_BC5_UNORM, BC5), // AKA BC5U
|
DXT4(0x34545844),
|
||||||
BC5U('B' + ('C' << 8) + ('5' << 16) + ('U' << 24), 16, DXGI.DXGI_FORMAT_BC5_UNORM, BC5),
|
DXT5(0x35545844),
|
||||||
BC5S('B' + ('C' << 8) + ('5' << 16) + ('S' << 24), 16, DXGI.DXGI_FORMAT_BC5_SNORM, BC5),
|
A1R5G5B5((1 << 16) | 2),
|
||||||
|
X1R5G5B5((2 << 16) | 2),
|
||||||
|
A4R4G4B4((3 << 16) | 2),
|
||||||
|
X4R4G4B4((4 << 16) | 2),
|
||||||
|
R5G6B5((5 << 16) | 2),
|
||||||
|
R8G8B8((1 << 16) | 3),
|
||||||
|
A8B8G8R8((1 << 16) | 4),
|
||||||
|
X8B8G8R8((2 << 16) | 4),
|
||||||
|
A8R8G8B8((3 << 16) | 4),
|
||||||
|
X8R8G8B8((4 << 16) | 4);
|
||||||
|
|
||||||
// Special case, see DXT10Header.dxgiFormat for real format
|
private final int value;
|
||||||
DXT10('D' + ('X' << 8) + ('1' << 16) + ('0' << 24), -1, DXGI.DXGI_FORMAT_UNKNOWN, null),
|
|
||||||
|
|
||||||
// Custom uncompressed pixel formats
|
DDSType(int value) {
|
||||||
// TODO: Consider swapping byte order to reflect the DXGI format?
|
this.value = value;
|
||||||
A1R5G5B5(2, DXGI.DXGI_FORMAT_B5G5R5A1_UNORM, A1R5G5B5_MASKS),
|
|
||||||
X1R5G5B5(2, DXGI.DXGI_FORMAT_UNKNOWN, X1R5G5B5_MASKS),
|
|
||||||
A4R4G4B4(2, DXGI.DXGI_FORMAT_B4G4R4A4_UNORM, A4R4G4B4_MASKS),
|
|
||||||
X4R4G4B4(2, DXGI.DXGI_FORMAT_UNKNOWN, X4R4G4B4_MASKS),
|
|
||||||
R5G6B5( 2, DXGI.DXGI_FORMAT_B5G6R5_UNORM, R5G6B5_MASKS),
|
|
||||||
R8G8B8( 3, DXGI.DXGI_FORMAT_UNKNOWN, R8G8B8_MASKS),
|
|
||||||
A8B8G8R8(4, DXGI.DXGI_FORMAT_R8G8B8A8_UNORM, A8B8G8R8_MASKS),
|
|
||||||
X8B8G8R8(4, DXGI.DXGI_FORMAT_UNKNOWN, X8B8G8R8_MASKS),
|
|
||||||
A8R8G8B8(4, DXGI.DXGI_FORMAT_B8G8R8A8_UNORM, A8R8G8B8_MASKS),
|
|
||||||
X8R8G8B8(4, DXGI.DXGI_FORMAT_B8G8R8X8_UNORM, X8R8G8B8_MASKS);
|
|
||||||
|
|
||||||
private final int fourCC;
|
|
||||||
private final int blockSize;
|
|
||||||
private final int dxgiFormat;
|
|
||||||
final BlockCompression compression;
|
|
||||||
final int[] rgbaMasks;
|
|
||||||
|
|
||||||
DDSType(int fourCC, int blockSize, int dxgiFormat, BlockCompression compression) {
|
|
||||||
this(fourCC, blockSize, dxgiFormat, compression, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DDSType(int blockSize, int dxgiFormat, int[] rgbaMasks) {
|
public int value() {
|
||||||
this(0, blockSize, dxgiFormat, null, rgbaMasks);
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
DDSType(int fourCC, int blockSize, int dxgiFormat, BlockCompression compression, int[] rgbaMasks) {
|
public static DDSType valueOf(int value) {
|
||||||
this.fourCC = fourCC;
|
for (DDSType type : DDSType.values()) {
|
||||||
this.blockSize = blockSize;
|
if (value == type.value()) {
|
||||||
this.dxgiFormat = dxgiFormat;
|
return type;
|
||||||
this.compression = compression;
|
|
||||||
this.rgbaMasks = rgbaMasks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int fourCC() {
|
|
||||||
return fourCC;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int blockSize() {
|
|
||||||
return blockSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isFourCC() {
|
|
||||||
return fourCC != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isBlockCompression() {
|
|
||||||
return compression != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int dxgiFormat() {
|
|
||||||
return dxgiFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DDSType fromFourCC(int fourCC) {
|
|
||||||
if (fourCC != 0) {
|
|
||||||
for (DDSType type : values()) {
|
|
||||||
if (fourCC == type.fourCC()) {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new IllegalArgumentException(String.format("Unknown type: 0x%08x", fourCC));
|
throw new IllegalArgumentException(String.format("Unknown type: 0x%08x", value));
|
||||||
}
|
|
||||||
|
|
||||||
public static DDSType fromDXGIFormat(int dxgiFormat) {
|
|
||||||
switch (dxgiFormat) {
|
|
||||||
case DXGI.DXGI_FORMAT_R8G8B8A8_TYPELESS:
|
|
||||||
case DXGI.DXGI_FORMAT_R8G8B8A8_UNORM:
|
|
||||||
case DXGI.DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
|
|
||||||
case DXGI.DXGI_FORMAT_R8G8B8A8_UINT:
|
|
||||||
return A8B8G8R8; // ABGR
|
|
||||||
|
|
||||||
case DXGI.DXGI_FORMAT_B8G8R8A8_TYPELESS:
|
|
||||||
case DXGI.DXGI_FORMAT_B8G8R8A8_UNORM:
|
|
||||||
case DXGI.DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
|
|
||||||
return A8R8G8B8; // ARGB
|
|
||||||
|
|
||||||
case DXGI.DXGI_FORMAT_B8G8R8X8_TYPELESS:
|
|
||||||
case DXGI.DXGI_FORMAT_B8G8R8X8_UNORM:
|
|
||||||
case DXGI.DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
|
|
||||||
return X8R8G8B8;
|
|
||||||
|
|
||||||
case DXGI.DXGI_FORMAT_B5G5R5A1_UNORM:
|
|
||||||
return A1R5G5B5;
|
|
||||||
|
|
||||||
case DXGI.DXGI_FORMAT_B4G4R4A4_UNORM:
|
|
||||||
return A4R4G4B4;
|
|
||||||
|
|
||||||
case DXGI.DXGI_FORMAT_B5G6R5_UNORM:
|
|
||||||
return R5G6B5;
|
|
||||||
|
|
||||||
case DXGI.DXGI_FORMAT_BC1_TYPELESS:
|
|
||||||
case DXGI.DXGI_FORMAT_BC1_UNORM:
|
|
||||||
case DXGI.DXGI_FORMAT_BC1_UNORM_SRGB:
|
|
||||||
return DXT1;
|
|
||||||
|
|
||||||
case DXGI.DXGI_FORMAT_BC2_TYPELESS:
|
|
||||||
case DXGI.DXGI_FORMAT_BC2_UNORM:
|
|
||||||
case DXGI.DXGI_FORMAT_BC2_UNORM_SRGB:
|
|
||||||
return DXT2;
|
|
||||||
|
|
||||||
case DXGI.DXGI_FORMAT_BC3_TYPELESS:
|
|
||||||
case DXGI.DXGI_FORMAT_BC3_UNORM:
|
|
||||||
case DXGI.DXGI_FORMAT_BC3_UNORM_SRGB:
|
|
||||||
return DXT4;
|
|
||||||
|
|
||||||
case DXGI.DXGI_FORMAT_BC4_TYPELESS:
|
|
||||||
case DXGI.DXGI_FORMAT_BC4_UNORM:
|
|
||||||
return BC4U;
|
|
||||||
|
|
||||||
case DXGI.DXGI_FORMAT_BC4_SNORM:
|
|
||||||
return BC4S;
|
|
||||||
|
|
||||||
case DXGI.DXGI_FORMAT_BC5_TYPELESS:
|
|
||||||
case DXGI.DXGI_FORMAT_BC5_UNORM:
|
|
||||||
return BC5U;
|
|
||||||
|
|
||||||
case DXGI.DXGI_FORMAT_BC5_SNORM:
|
|
||||||
return BC5S;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Unsupported DXGI_FORMAT: " + dxgiFormat);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,129 +0,0 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.dds;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <a href="https://learn.microsoft.com/en-us/windows/win32/api/dxgiformat/ne-dxgiformat-dxgi_format">DXGI Format List</a>
|
|
||||||
*/
|
|
||||||
interface DXGI {
|
|
||||||
int DXGI_FORMAT_UNKNOWN = 0;
|
|
||||||
int DXGI_FORMAT_R32G32B32A32_TYPELESS = 1;
|
|
||||||
int DXGI_FORMAT_R32G32B32A32_FLOAT = 2;
|
|
||||||
int DXGI_FORMAT_R32G32B32A32_UINT = 3;
|
|
||||||
int DXGI_FORMAT_R32G32B32A32_SINT = 4;
|
|
||||||
int DXGI_FORMAT_R32G32B32_TYPELESS = 5;
|
|
||||||
int DXGI_FORMAT_R32G32B32_FLOAT = 6;
|
|
||||||
int DXGI_FORMAT_R32G32B32_UINT = 7;
|
|
||||||
int DXGI_FORMAT_R32G32B32_SINT = 8;
|
|
||||||
int DXGI_FORMAT_R16G16B16A16_TYPELESS = 9;
|
|
||||||
int DXGI_FORMAT_R16G16B16A16_FLOAT = 10;
|
|
||||||
int DXGI_FORMAT_R16G16B16A16_UNORM = 11;
|
|
||||||
int DXGI_FORMAT_R16G16B16A16_UINT = 12;
|
|
||||||
int DXGI_FORMAT_R16G16B16A16_SNORM = 13;
|
|
||||||
int DXGI_FORMAT_R16G16B16A16_SINT = 14;
|
|
||||||
int DXGI_FORMAT_R32G32_TYPELESS = 15;
|
|
||||||
int DXGI_FORMAT_R32G32_FLOAT = 16;
|
|
||||||
int DXGI_FORMAT_R32G32_UINT = 17;
|
|
||||||
int DXGI_FORMAT_R32G32_SINT = 18;
|
|
||||||
int DXGI_FORMAT_R32G8X24_TYPELESS = 19;
|
|
||||||
int DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20;
|
|
||||||
int DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21;
|
|
||||||
int DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22;
|
|
||||||
int DXGI_FORMAT_R10G10B10A2_TYPELESS = 23;
|
|
||||||
int DXGI_FORMAT_R10G10B10A2_UNORM = 24;
|
|
||||||
int DXGI_FORMAT_R10G10B10A2_UINT = 25;
|
|
||||||
int DXGI_FORMAT_R11G11B10_FLOAT = 26;
|
|
||||||
int DXGI_FORMAT_R8G8B8A8_TYPELESS = 27;
|
|
||||||
int DXGI_FORMAT_R8G8B8A8_UNORM = 28;
|
|
||||||
int DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29;
|
|
||||||
int DXGI_FORMAT_R8G8B8A8_UINT = 30;
|
|
||||||
int DXGI_FORMAT_R8G8B8A8_SNORM = 31;
|
|
||||||
int DXGI_FORMAT_R8G8B8A8_SINT = 32;
|
|
||||||
int DXGI_FORMAT_R16G16_TYPELESS = 33;
|
|
||||||
int DXGI_FORMAT_R16G16_FLOAT = 34;
|
|
||||||
int DXGI_FORMAT_R16G16_UNORM = 35;
|
|
||||||
int DXGI_FORMAT_R16G16_UINT = 36;
|
|
||||||
int DXGI_FORMAT_R16G16_SNORM = 37;
|
|
||||||
int DXGI_FORMAT_R16G16_SINT = 38;
|
|
||||||
int DXGI_FORMAT_R32_TYPELESS = 39;
|
|
||||||
int DXGI_FORMAT_D32_FLOAT = 40;
|
|
||||||
int DXGI_FORMAT_R32_FLOAT = 41;
|
|
||||||
int DXGI_FORMAT_R32_UINT = 42;
|
|
||||||
int DXGI_FORMAT_R32_SINT = 43;
|
|
||||||
int DXGI_FORMAT_R24G8_TYPELESS = 44;
|
|
||||||
int DXGI_FORMAT_D24_UNORM_S8_UINT = 45;
|
|
||||||
int DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46;
|
|
||||||
int DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47;
|
|
||||||
int DXGI_FORMAT_R8G8_TYPELESS = 48;
|
|
||||||
int DXGI_FORMAT_R8G8_UNORM = 49;
|
|
||||||
int DXGI_FORMAT_R8G8_UINT = 50;
|
|
||||||
int DXGI_FORMAT_R8G8_SNORM = 51;
|
|
||||||
int DXGI_FORMAT_R8G8_SINT = 52;
|
|
||||||
int DXGI_FORMAT_R16_TYPELESS = 53;
|
|
||||||
int DXGI_FORMAT_R16_FLOAT = 54;
|
|
||||||
int DXGI_FORMAT_D16_UNORM = 55;
|
|
||||||
int DXGI_FORMAT_R16_UNORM = 56;
|
|
||||||
int DXGI_FORMAT_R16_UINT = 57;
|
|
||||||
int DXGI_FORMAT_R16_SNORM = 58;
|
|
||||||
int DXGI_FORMAT_R16_SINT = 59;
|
|
||||||
int DXGI_FORMAT_R8_TYPELESS = 60;
|
|
||||||
int DXGI_FORMAT_R8_UNORM = 61;
|
|
||||||
int DXGI_FORMAT_R8_UINT = 62;
|
|
||||||
int DXGI_FORMAT_R8_SNORM = 63;
|
|
||||||
int DXGI_FORMAT_R8_SINT = 64;
|
|
||||||
int DXGI_FORMAT_A8_UNORM = 65;
|
|
||||||
int DXGI_FORMAT_R1_UNORM = 66;
|
|
||||||
int DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67;
|
|
||||||
int DXGI_FORMAT_R8G8_B8G8_UNORM = 68;
|
|
||||||
int DXGI_FORMAT_G8R8_G8B8_UNORM = 69;
|
|
||||||
int DXGI_FORMAT_BC1_TYPELESS = 70;
|
|
||||||
int DXGI_FORMAT_BC1_UNORM = 71;
|
|
||||||
int DXGI_FORMAT_BC1_UNORM_SRGB = 72;
|
|
||||||
int DXGI_FORMAT_BC2_TYPELESS = 73;
|
|
||||||
int DXGI_FORMAT_BC2_UNORM = 74;
|
|
||||||
int DXGI_FORMAT_BC2_UNORM_SRGB = 75;
|
|
||||||
int DXGI_FORMAT_BC3_TYPELESS = 76;
|
|
||||||
int DXGI_FORMAT_BC3_UNORM = 77;
|
|
||||||
int DXGI_FORMAT_BC3_UNORM_SRGB = 78;
|
|
||||||
int DXGI_FORMAT_BC4_TYPELESS = 79;
|
|
||||||
int DXGI_FORMAT_BC4_UNORM = 80;
|
|
||||||
int DXGI_FORMAT_BC4_SNORM = 81;
|
|
||||||
int DXGI_FORMAT_BC5_TYPELESS = 82;
|
|
||||||
int DXGI_FORMAT_BC5_UNORM = 83;
|
|
||||||
int DXGI_FORMAT_BC5_SNORM = 84;
|
|
||||||
int DXGI_FORMAT_B5G6R5_UNORM = 85;
|
|
||||||
int DXGI_FORMAT_B5G5R5A1_UNORM = 86;
|
|
||||||
int DXGI_FORMAT_B8G8R8A8_UNORM = 87;
|
|
||||||
int DXGI_FORMAT_B8G8R8X8_UNORM = 88;
|
|
||||||
int DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89;
|
|
||||||
int DXGI_FORMAT_B8G8R8A8_TYPELESS = 90;
|
|
||||||
int DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91;
|
|
||||||
int DXGI_FORMAT_B8G8R8X8_TYPELESS = 92;
|
|
||||||
int DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93;
|
|
||||||
int DXGI_FORMAT_BC6H_TYPELESS = 94;
|
|
||||||
int DXGI_FORMAT_BC6H_UF16 = 95;
|
|
||||||
int DXGI_FORMAT_BC6H_SF16 = 96;
|
|
||||||
int DXGI_FORMAT_BC7_TYPELESS = 97;
|
|
||||||
int DXGI_FORMAT_BC7_UNORM = 98;
|
|
||||||
int DXGI_FORMAT_BC7_UNORM_SRGB = 99;
|
|
||||||
int DXGI_FORMAT_AYUV = 100;
|
|
||||||
int DXGI_FORMAT_Y410 = 101;
|
|
||||||
int DXGI_FORMAT_Y416 = 102;
|
|
||||||
int DXGI_FORMAT_NV12 = 103;
|
|
||||||
int DXGI_FORMAT_P010 = 104;
|
|
||||||
int DXGI_FORMAT_P016 = 105;
|
|
||||||
int DXGI_FORMAT_420_OPAQUE = 106;
|
|
||||||
int DXGI_FORMAT_YUY2 = 107;
|
|
||||||
int DXGI_FORMAT_Y210 = 108;
|
|
||||||
int DXGI_FORMAT_Y216 = 109;
|
|
||||||
int DXGI_FORMAT_NV11 = 110;
|
|
||||||
int DXGI_FORMAT_AI44 = 111;
|
|
||||||
int DXGI_FORMAT_IA44 = 112;
|
|
||||||
int DXGI_FORMAT_P8 = 113;
|
|
||||||
int DXGI_FORMAT_A8P8 = 114;
|
|
||||||
int DXGI_FORMAT_B4G4R4A4_UNORM = 115;
|
|
||||||
int DXGI_FORMAT_P208 = 130;
|
|
||||||
int DXGI_FORMAT_V208 = 131;
|
|
||||||
int DXGI_FORMAT_V408 = 132;
|
|
||||||
int DXGI_FORMAT_SAMPLER_FEEDBACK_MIN_MIP_OPAQUE = 189;
|
|
||||||
int DXGI_FORMAT_SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE = 190;
|
|
||||||
int DXGI_FORMAT_FORCE_UINT = 0xffffffff;
|
|
||||||
}
|
|
||||||
-45
@@ -1,45 +0,0 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.dds;
|
|
||||||
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see <a href="https://learn.microsoft.com/en-us/windows/win32/direct3ddds/dds-header-dxt10">DDS_HEADER_DXT10 structure</a>
|
|
||||||
*/
|
|
||||||
final class DXT10Header {
|
|
||||||
final int dxgiFormat;
|
|
||||||
final int resourceDimension;
|
|
||||||
final int miscFlag;
|
|
||||||
final int arraySize;
|
|
||||||
final int miscFlags2;
|
|
||||||
|
|
||||||
private final DDSType type;
|
|
||||||
|
|
||||||
private DXT10Header(int dxgiFormat, int resourceDimension, int miscFlag, int arraySize, int miscFlags2) {
|
|
||||||
type = DDSType.fromDXGIFormat(dxgiFormat); // Validates dxgiFormat
|
|
||||||
if (resourceDimension != DDS.D3D10_RESOURCE_DIMENSION_TEXTURE2D) {
|
|
||||||
throw new IllegalArgumentException(String.format("Resource dimension %d is not supported, expected: %d",
|
|
||||||
resourceDimension, DDS.D3D10_RESOURCE_DIMENSION_TEXTURE2D));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.dxgiFormat = dxgiFormat;
|
|
||||||
this.resourceDimension = resourceDimension;
|
|
||||||
this.miscFlag = miscFlag;
|
|
||||||
this.arraySize = arraySize;
|
|
||||||
this.miscFlags2 = miscFlags2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static DXT10Header read(ImageInputStream inputStream) throws IOException {
|
|
||||||
int dxgiFormat = inputStream.readInt();
|
|
||||||
int resourceDimension = inputStream.readInt();
|
|
||||||
int miscFlag = inputStream.readInt();
|
|
||||||
int arraySize = inputStream.readInt();
|
|
||||||
int miscFlags2 = inputStream.readInt();
|
|
||||||
|
|
||||||
return new DXT10Header(dxgiFormat, resourceDimension, miscFlag, arraySize, miscFlags2);
|
|
||||||
}
|
|
||||||
|
|
||||||
DDSType getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-1
@@ -1 +0,0 @@
|
|||||||
com.twelvemonkeys.imageio.plugins.dds.DDSImageWriterSpi
|
|
||||||
-101
@@ -1,101 +0,0 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.dds;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
|
|
||||||
import javax.imageio.ImageTypeSpecifier;
|
|
||||||
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
|
||||||
import javax.imageio.metadata.IIOMetadataNode;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.w3c.dom.NodeList;
|
|
||||||
|
|
||||||
class DDSImageMetadataTest {
|
|
||||||
@Test
|
|
||||||
void standardMetadataDXT1() {
|
|
||||||
DDSImageMetadata metadata = createDDSImageMetadata(BufferedImage.TYPE_INT_ARGB, DDSType.DXT1);
|
|
||||||
IIOMetadataNode tree = (IIOMetadataNode) metadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
|
|
||||||
|
|
||||||
NodeList compressionTypeNames = tree.getElementsByTagName("CompressionTypeName");
|
|
||||||
assertEquals(1, compressionTypeNames.getLength());
|
|
||||||
IIOMetadataNode compressionTypeName = (IIOMetadataNode) compressionTypeNames.item(0);
|
|
||||||
assertEquals("DXT1", compressionTypeName.getAttribute("value"));
|
|
||||||
|
|
||||||
NodeList losslesses = tree.getElementsByTagName("Lossless");
|
|
||||||
assertEquals(1, losslesses.getLength());
|
|
||||||
IIOMetadataNode lossless = (IIOMetadataNode) losslesses.item(0);
|
|
||||||
assertEquals("FALSE", lossless.getAttribute("value"));
|
|
||||||
|
|
||||||
NodeList bitsPerSamples = tree.getElementsByTagName("BitsPerSample");
|
|
||||||
assertEquals(1, bitsPerSamples.getLength());
|
|
||||||
IIOMetadataNode bitsPerSample = (IIOMetadataNode) bitsPerSamples.item(0);
|
|
||||||
assertEquals("8 8 8 8", bitsPerSample.getAttribute("value"));
|
|
||||||
|
|
||||||
NodeList alphas = tree.getElementsByTagName("Alpha");
|
|
||||||
assertEquals(1, alphas.getLength());
|
|
||||||
IIOMetadataNode alpha = (IIOMetadataNode) alphas.item(0);
|
|
||||||
assertEquals("nonpremultiplied", alpha.getAttribute("value"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void standardMetadataA8R8G8B8() {
|
|
||||||
DDSImageMetadata metadata = createDDSImageMetadata(BufferedImage.TYPE_INT_ARGB, DDSType.A8R8G8B8);
|
|
||||||
IIOMetadataNode tree = (IIOMetadataNode) metadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
|
|
||||||
|
|
||||||
NodeList compressions = tree.getElementsByTagName("Compression");
|
|
||||||
assertEquals(0, compressions.getLength());
|
|
||||||
|
|
||||||
NodeList bitsPerSamples = tree.getElementsByTagName("BitsPerSample");
|
|
||||||
assertEquals(1, bitsPerSamples.getLength());
|
|
||||||
IIOMetadataNode bitsPerSample = (IIOMetadataNode) bitsPerSamples.item(0);
|
|
||||||
assertEquals("8 8 8 8", bitsPerSample.getAttribute("value"));
|
|
||||||
|
|
||||||
NodeList alphas = tree.getElementsByTagName("Alpha");
|
|
||||||
assertEquals(1, alphas.getLength());
|
|
||||||
IIOMetadataNode alpha = (IIOMetadataNode) alphas.item(0);
|
|
||||||
assertEquals("nonpremultiplied", alpha.getAttribute("value"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void standardMetadataX8R8G8B8() {
|
|
||||||
DDSImageMetadata metadata = createDDSImageMetadata(BufferedImage.TYPE_INT_RGB, DDSType.X8R8G8B8);
|
|
||||||
IIOMetadataNode tree = (IIOMetadataNode) metadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
|
|
||||||
|
|
||||||
NodeList compressions = tree.getElementsByTagName("Compression");
|
|
||||||
assertEquals(0, compressions.getLength());
|
|
||||||
|
|
||||||
NodeList bitsPerSamples = tree.getElementsByTagName("BitsPerSample");
|
|
||||||
assertEquals(1, bitsPerSamples.getLength());
|
|
||||||
IIOMetadataNode bitsPerSample = (IIOMetadataNode) bitsPerSamples.item(0);
|
|
||||||
assertEquals("8 8 8 0", bitsPerSample.getAttribute("value")); // Or just 8 8 8?
|
|
||||||
|
|
||||||
NodeList alphas = tree.getElementsByTagName("Alpha");
|
|
||||||
assertEquals(1, alphas.getLength());
|
|
||||||
IIOMetadataNode alpha = (IIOMetadataNode) alphas.item(0);
|
|
||||||
assertEquals("none", alpha.getAttribute("value"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void standardMetadataX1R5G5B5() {
|
|
||||||
DDSImageMetadata metadata = createDDSImageMetadata(BufferedImage.TYPE_INT_RGB, DDSType.X1R5G5B5);
|
|
||||||
IIOMetadataNode tree = (IIOMetadataNode) metadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
|
|
||||||
|
|
||||||
NodeList compressions = tree.getElementsByTagName("Compression");
|
|
||||||
assertEquals(0, compressions.getLength());
|
|
||||||
|
|
||||||
NodeList bitsPerSamples = tree.getElementsByTagName("BitsPerSample");
|
|
||||||
assertEquals(1, bitsPerSamples.getLength());
|
|
||||||
IIOMetadataNode bitsPerSample = (IIOMetadataNode) bitsPerSamples.item(0);
|
|
||||||
assertEquals("5 5 5 0", bitsPerSample.getAttribute("value")); // Or just 5 5 5?
|
|
||||||
|
|
||||||
NodeList alphas = tree.getElementsByTagName("Alpha");
|
|
||||||
assertEquals(1, alphas.getLength());
|
|
||||||
IIOMetadataNode alpha = (IIOMetadataNode) alphas.item(0);
|
|
||||||
assertEquals("none", alpha.getAttribute("value"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static DDSImageMetadata createDDSImageMetadata(int bufferedImageType, DDSType ddsType) {
|
|
||||||
return new DDSImageMetadata(ImageTypeSpecifier.createFromBufferedImageType(bufferedImageType), ddsType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
-83
@@ -30,27 +30,14 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.dds;
|
package com.twelvemonkeys.imageio.plugins.dds;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import javax.imageio.ImageReader;
|
|
||||||
import javax.imageio.metadata.IIOMetadata;
|
|
||||||
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
|
||||||
import javax.imageio.metadata.IIOMetadataNode;
|
|
||||||
import javax.imageio.spi.ImageReaderSpi;
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
|
||||||
|
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.w3c.dom.NodeList;
|
|
||||||
|
|
||||||
public class DDSImageReaderTest extends ImageReaderAbstractTest<DDSImageReader> {
|
public class DDSImageReaderTest extends ImageReaderAbstractTest<DDSImageReader> {
|
||||||
@Override
|
@Override
|
||||||
protected ImageReaderSpi createProvider() {
|
protected ImageReaderSpi createProvider() {
|
||||||
@@ -99,13 +86,7 @@ public class DDSImageReaderTest extends ImageReaderAbstractTest<DDSImageReader>
|
|||||||
new TestData(getClassLoaderResource("/dds/dds_X8B8G8R8.dds"), dim256),
|
new TestData(getClassLoaderResource("/dds/dds_X8B8G8R8.dds"), dim256),
|
||||||
new TestData(getClassLoaderResource("/dds/dds_X8B8G8R8_mipmap.dds"), dim256, dim128, dim64),
|
new TestData(getClassLoaderResource("/dds/dds_X8B8G8R8_mipmap.dds"), dim256, dim128, dim64),
|
||||||
new TestData(getClassLoaderResource("/dds/dds_X8R8G8B8.dds"), dim256),
|
new TestData(getClassLoaderResource("/dds/dds_X8R8G8B8.dds"), dim256),
|
||||||
new TestData(getClassLoaderResource("/dds/dds_X8R8G8B8_mipmap.dds"), dim256, dim128, dim64),
|
new TestData(getClassLoaderResource("/dds/dds_X8R8G8B8_mipmap.dds"), dim256, dim128, dim64)
|
||||||
new TestData(getClassLoaderResource("/dds/dxt10_BC1_sRGB.dds"), dim256),
|
|
||||||
new TestData(getClassLoaderResource("/dds/dxt10_BC2_sRGB.dds"), dim256),
|
|
||||||
new TestData(getClassLoaderResource("/dds/dxt10_BC3_sRGB.dds"), dim256),
|
|
||||||
new TestData(getClassLoaderResource("/dds/dxt10_B8G8R8A8.dds"), dim256),
|
|
||||||
new TestData(getClassLoaderResource("/dds/dxt10_B8G8R8X8.dds"), dim256),
|
|
||||||
new TestData(getClassLoaderResource("/dds/dxt10_R8G8B8A8.dds"), dim256)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,67 +104,4 @@ public class DDSImageReaderTest extends ImageReaderAbstractTest<DDSImageReader>
|
|||||||
protected List<String> getMIMETypes() {
|
protected List<String> getMIMETypes() {
|
||||||
return Collections.singletonList("image/vnd-ms.dds");
|
return Collections.singletonList("image/vnd-ms.dds");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void metadataDXT5() throws IOException {
|
|
||||||
ImageReader reader = createReader();
|
|
||||||
|
|
||||||
try (ImageInputStream inputStream = ImageIO.createImageInputStream(getClassLoaderResource("/dds/dds_DXT5.dds"))) {
|
|
||||||
reader.setInput(inputStream);
|
|
||||||
|
|
||||||
IIOMetadata metadata = reader.getImageMetadata(0);
|
|
||||||
IIOMetadataNode tree = (IIOMetadataNode) metadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
|
|
||||||
|
|
||||||
NodeList compressionTypeNames = tree.getElementsByTagName("CompressionTypeName");
|
|
||||||
assertEquals(1, compressionTypeNames.getLength());
|
|
||||||
IIOMetadataNode compressionTypeName = (IIOMetadataNode) compressionTypeNames.item(0);
|
|
||||||
assertEquals("DXT5", compressionTypeName.getAttribute("value"));
|
|
||||||
|
|
||||||
NodeList losslesses = tree.getElementsByTagName("Lossless");
|
|
||||||
assertEquals(1, losslesses.getLength());
|
|
||||||
IIOMetadataNode lossless = (IIOMetadataNode) losslesses.item(0);
|
|
||||||
assertEquals("FALSE", lossless.getAttribute("value"));
|
|
||||||
|
|
||||||
NodeList bitsPerSamples = tree.getElementsByTagName("BitsPerSample");
|
|
||||||
assertEquals(1, bitsPerSamples.getLength());
|
|
||||||
IIOMetadataNode bitsPerSample = (IIOMetadataNode) bitsPerSamples.item(0);
|
|
||||||
assertEquals("8 8 8 8", bitsPerSample.getAttribute("value"));
|
|
||||||
|
|
||||||
NodeList alphas = tree.getElementsByTagName("Alpha");
|
|
||||||
assertEquals(1, alphas.getLength());
|
|
||||||
IIOMetadataNode alpha = (IIOMetadataNode) alphas.item(0);
|
|
||||||
assertEquals("nonpremultiplied", alpha.getAttribute("value"));
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
reader.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void metadataRGB565() throws IOException {
|
|
||||||
ImageReader reader = createReader();
|
|
||||||
|
|
||||||
try (ImageInputStream inputStream = ImageIO.createImageInputStream(getClassLoaderResource("/dds/dds_R5G6B5.dds"))) {
|
|
||||||
reader.setInput(inputStream);
|
|
||||||
|
|
||||||
IIOMetadata metadata = reader.getImageMetadata(0);
|
|
||||||
IIOMetadataNode tree = (IIOMetadataNode) metadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
|
|
||||||
|
|
||||||
NodeList compressions = tree.getElementsByTagName("Compression");
|
|
||||||
assertEquals(0, compressions.getLength());
|
|
||||||
|
|
||||||
NodeList bitsPerSamples = tree.getElementsByTagName("BitsPerSample");
|
|
||||||
assertEquals(1, bitsPerSamples.getLength());
|
|
||||||
IIOMetadataNode bitsPerSample = (IIOMetadataNode) bitsPerSamples.item(0);
|
|
||||||
assertEquals("5 6 5 0", bitsPerSample.getAttribute("value")); // or "5 6 5"
|
|
||||||
|
|
||||||
NodeList alphas = tree.getElementsByTagName("Alpha");
|
|
||||||
assertEquals(1, alphas.getLength());
|
|
||||||
IIOMetadataNode alpha = (IIOMetadataNode) alphas.item(0);
|
|
||||||
assertEquals("none", alpha.getAttribute("value"));
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
reader.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
-55
@@ -1,55 +0,0 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.dds;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import javax.imageio.ImageWriteParam;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
class DDSImageWriteParamTest {
|
|
||||||
@Test
|
|
||||||
void defaultParam() {
|
|
||||||
DDSImageWriteParam param = new DDSImageWriteParam();
|
|
||||||
assertEquals(DDSImageWriteParam.DEFAULT_TYPE, param.type());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void compressionTypes() {
|
|
||||||
DDSImageWriteParam param = new DDSImageWriteParam();
|
|
||||||
|
|
||||||
String[] compressionTypes = param.getCompressionTypes();
|
|
||||||
DDSType[] values = Arrays.stream(DDSType.values())
|
|
||||||
.filter(DDSType::isBlockCompression)
|
|
||||||
.toArray(DDSType[]::new);
|
|
||||||
|
|
||||||
assertEquals(values.length + 1, compressionTypes.length);
|
|
||||||
|
|
||||||
for (int i = 0; i < values.length; i++) {
|
|
||||||
DDSType type = values[i];
|
|
||||||
assertEquals(type.name(), compressionTypes[i + 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
assertEquals("None", compressionTypes[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void setCompression() {
|
|
||||||
DDSImageWriteParam param = new DDSImageWriteParam();
|
|
||||||
|
|
||||||
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
|
||||||
|
|
||||||
String[] compressionTypes = param.getCompressionTypes();
|
|
||||||
for (String compressionType : compressionTypes) {
|
|
||||||
param.setCompressionType(compressionType);
|
|
||||||
assertEquals(compressionType, param.getCompressionType());
|
|
||||||
|
|
||||||
if (!"None".equals(compressionType)) {
|
|
||||||
DDSType type = DDSType.valueOf(compressionType);
|
|
||||||
|
|
||||||
assertEquals(type, param.type());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-186
@@ -1,186 +0,0 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.dds;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.util.ImageWriterAbstractTest;
|
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
|
||||||
import javax.imageio.IIOImage;
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import javax.imageio.ImageReader;
|
|
||||||
import javax.imageio.ImageWriteParam;
|
|
||||||
import javax.imageio.ImageWriter;
|
|
||||||
import javax.imageio.event.IIOWriteWarningListener;
|
|
||||||
import javax.imageio.spi.ImageWriterSpi;
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
|
||||||
import javax.imageio.stream.ImageOutputStream;
|
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
class DDSImageWriterTest extends ImageWriterAbstractTest<DDSImageWriter> {
|
|
||||||
@Override
|
|
||||||
protected ImageWriterSpi createProvider() {
|
|
||||||
return new DDSImageWriterSpi();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected List<BufferedImage> getTestData() {
|
|
||||||
return Arrays.asList(
|
|
||||||
new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB),
|
|
||||||
new BufferedImage(128, 128, BufferedImage.TYPE_INT_ARGB),
|
|
||||||
new BufferedImage(64, 64, BufferedImage.TYPE_INT_RGB),
|
|
||||||
new BufferedImage(32, 32, BufferedImage.TYPE_4BYTE_ABGR),
|
|
||||||
new BufferedImage(16, 16, BufferedImage.TYPE_3BYTE_BGR)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void writeRasters() throws IOException {
|
|
||||||
ImageWriter writer = createWriter();
|
|
||||||
|
|
||||||
assertTrue(writer.canWriteRasters());
|
|
||||||
|
|
||||||
// Full tests in super class
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void writeMipmap() throws IOException {
|
|
||||||
ImageWriter writer = createWriter();
|
|
||||||
|
|
||||||
try {
|
|
||||||
assertTrue(writer.canWriteSequence());
|
|
||||||
|
|
||||||
List<BufferedImage> testData = getTestData();
|
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
|
||||||
int previousSize = 0;
|
|
||||||
|
|
||||||
try (ImageOutputStream stream = ImageIO.createImageOutputStream(buffer)) {
|
|
||||||
writer.setOutput(stream);
|
|
||||||
writer.prepareWriteSequence(null);
|
|
||||||
ImageWriteParam param = writer.getDefaultWriteParam();
|
|
||||||
|
|
||||||
assertTrue(buffer.size() > previousSize);
|
|
||||||
previousSize = buffer.size();
|
|
||||||
|
|
||||||
for (BufferedImage image : testData) {
|
|
||||||
writer.writeToSequence(new IIOImage(drawSomething(image), null, null), param);
|
|
||||||
}
|
|
||||||
|
|
||||||
writer.endWriteSequence();
|
|
||||||
assertTrue(buffer.size() > previousSize, "No image data written");
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
throw new AssertionError(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify that we can read the file back...
|
|
||||||
ImageReader reader = ImageIO.getImageReader(writer);
|
|
||||||
|
|
||||||
try (ImageInputStream stream = ImageIO.createImageInputStream(new ByteArrayInputStream(buffer.toByteArray()))) {
|
|
||||||
stream.seek(0);
|
|
||||||
reader.setInput(stream);
|
|
||||||
|
|
||||||
assertEquals(testData.size(), reader.getNumImages(false));
|
|
||||||
|
|
||||||
for (int i = 0; i < testData.size(); i++) {
|
|
||||||
BufferedImage image = reader.read(i, null);
|
|
||||||
|
|
||||||
assertNotNull(image);
|
|
||||||
assertEquals(testData.get(i).getWidth(), image.getWidth());
|
|
||||||
assertEquals(testData.get(i).getHeight(), image.getHeight());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
reader.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
writer.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void writeMipmapDifferentCompression() throws IOException {
|
|
||||||
ImageWriter writer = createWriter();
|
|
||||||
|
|
||||||
try {
|
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
try (ImageOutputStream stream = ImageIO.createImageOutputStream(buffer)) {
|
|
||||||
IIOWriteWarningListener listener = mock();
|
|
||||||
writer.addIIOWriteWarningListener(listener);
|
|
||||||
writer.setOutput(stream);
|
|
||||||
|
|
||||||
writer.prepareWriteSequence(null);
|
|
||||||
ImageWriteParam param = writer.getDefaultWriteParam();
|
|
||||||
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
|
||||||
param.setCompressionType("DXT2");
|
|
||||||
|
|
||||||
// Write first with DXT2
|
|
||||||
List<BufferedImage> testData = getTestData();
|
|
||||||
writer.writeToSequence(new IIOImage(drawSomething(testData.get(0)), null, null), param);
|
|
||||||
|
|
||||||
// Repeat with different type
|
|
||||||
IIOImage image = new IIOImage(drawSomething(testData.get(1)), null, null);
|
|
||||||
param.setCompressionType("DXT1");
|
|
||||||
|
|
||||||
writer.writeToSequence(image, param);
|
|
||||||
|
|
||||||
// Verify warning is issued
|
|
||||||
verify(listener).warningOccurred(eq(writer), eq(1), anyString());
|
|
||||||
verifyNoMoreInteractions(listener);
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
throw new AssertionError(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
writer.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void writeMipmapUnexpectedSize() throws IOException {
|
|
||||||
ImageWriter writer = createWriter();
|
|
||||||
|
|
||||||
try {
|
|
||||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
try (ImageOutputStream stream = ImageIO.createImageOutputStream(buffer)) {
|
|
||||||
writer.setOutput(stream);
|
|
||||||
|
|
||||||
writer.prepareWriteSequence(null);
|
|
||||||
ImageWriteParam param = writer.getDefaultWriteParam();
|
|
||||||
BufferedImage testData = getTestData().get(0);
|
|
||||||
|
|
||||||
IIOImage image = new IIOImage(drawSomething(testData), null, null);
|
|
||||||
writer.writeToSequence(image, param);
|
|
||||||
|
|
||||||
// Repeat with same size... boom.
|
|
||||||
assertThrows(IIOException.class, () -> writer.writeToSequence(image, param));
|
|
||||||
}
|
|
||||||
catch (IOException e) {
|
|
||||||
throw new AssertionError(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
writer.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -4,10 +4,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-hdr</artifactId>
|
<artifactId>imageio-hdr</artifactId>
|
||||||
<name>TwelveMonkeys » ImageIO » HDR plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: HDR plugin</name>
|
||||||
<description>
|
<description>
|
||||||
ImageIO plugin for Radiance RGBE High Dynaimc Range format (HDR).
|
ImageIO plugin for Radiance RGBE High Dynaimc Range format (HDR).
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-icns</artifactId>
|
<artifactId>imageio-icns</artifactId>
|
||||||
<name>TwelveMonkeys » ImageIO » ICNS plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: ICNS plugin</name>
|
||||||
<description>ImageIO plugin for Apple Icon Image (ICNS) format.</description>
|
<description>ImageIO plugin for Apple Icon Image (ICNS) format.</description>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
|||||||
+19
-8
@@ -33,7 +33,6 @@ package com.twelvemonkeys.imageio.plugins.icns;
|
|||||||
import com.twelvemonkeys.imageio.ImageWriterBase;
|
import com.twelvemonkeys.imageio.ImageWriterBase;
|
||||||
import com.twelvemonkeys.imageio.stream.SubImageOutputStream;
|
import com.twelvemonkeys.imageio.stream.SubImageOutputStream;
|
||||||
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
||||||
import com.twelvemonkeys.imageio.util.SequenceSupport;
|
|
||||||
|
|
||||||
import javax.imageio.IIOException;
|
import javax.imageio.IIOException;
|
||||||
import javax.imageio.IIOImage;
|
import javax.imageio.IIOImage;
|
||||||
@@ -56,7 +55,7 @@ import java.util.Iterator;
|
|||||||
*/
|
*/
|
||||||
public final class ICNSImageWriter extends ImageWriterBase {
|
public final class ICNSImageWriter extends ImageWriterBase {
|
||||||
|
|
||||||
private final SequenceSupport sequence = new SequenceSupport();
|
private int sequenceIndex = -1;
|
||||||
private ImageWriter pngDelegate;
|
private ImageWriter pngDelegate;
|
||||||
|
|
||||||
ICNSImageWriter(ImageWriterSpi provider) {
|
ICNSImageWriter(ImageWriterSpi provider) {
|
||||||
@@ -65,7 +64,7 @@ public final class ICNSImageWriter extends ImageWriterBase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void resetMembers() {
|
protected void resetMembers() {
|
||||||
sequence.reset();
|
sequenceIndex = -1;
|
||||||
|
|
||||||
if (pngDelegate != null) {
|
if (pngDelegate != null) {
|
||||||
pngDelegate.dispose();
|
pngDelegate.dispose();
|
||||||
@@ -98,29 +97,41 @@ public final class ICNSImageWriter extends ImageWriterBase {
|
|||||||
@Override
|
@Override
|
||||||
public void prepareWriteSequence(final IIOMetadata streamMetadata) throws IOException {
|
public void prepareWriteSequence(final IIOMetadata streamMetadata) throws IOException {
|
||||||
assertOutput();
|
assertOutput();
|
||||||
sequence.start();
|
|
||||||
|
|
||||||
// TODO: Allow TOC resource to be passed as stream metadata?
|
// TODO: Allow TOC resource to be passed as stream metadata?
|
||||||
// - We only need number of icons to be written later
|
// - We only need number of icons to be written later
|
||||||
// - The contents of the TOC could be updated while adding to the sequence
|
// - The contents of the TOC could be updated while adding to the sequence
|
||||||
|
|
||||||
|
if (sequenceIndex >= 0) {
|
||||||
|
throw new IllegalStateException("writeSequence already started");
|
||||||
|
}
|
||||||
|
|
||||||
writeICNSHeader();
|
writeICNSHeader();
|
||||||
|
sequenceIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("RedundantThrows")
|
@SuppressWarnings("RedundantThrows")
|
||||||
@Override
|
@Override
|
||||||
public void endWriteSequence() throws IOException {
|
public void endWriteSequence() throws IOException {
|
||||||
assertOutput();
|
assertOutput();
|
||||||
sequence.end();
|
|
||||||
|
if (sequenceIndex < 0) {
|
||||||
|
throw new IllegalStateException("prepareWriteSequence not called");
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Now that we know the number of icon resources, we could move all data backwards
|
// TODO: Now that we know the number of icon resources, we could move all data backwards
|
||||||
// and write a TOC... But I don't think the benefit will outweigh the cost.
|
// and write a TOC... But I don't think the benefit will outweigh the cost.
|
||||||
|
|
||||||
|
sequenceIndex = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeToSequence(final IIOImage image, final ImageWriteParam param) throws IOException {
|
public void writeToSequence(final IIOImage image, final ImageWriteParam param) throws IOException {
|
||||||
assertOutput();
|
assertOutput();
|
||||||
int imageIndex = sequence.advance();
|
|
||||||
|
if (sequenceIndex < 0) {
|
||||||
|
throw new IllegalStateException("prepareWriteSequence not called");
|
||||||
|
}
|
||||||
|
|
||||||
if (image.hasRaster()) {
|
if (image.hasRaster()) {
|
||||||
throw new UnsupportedOperationException("image has a Raster");
|
throw new UnsupportedOperationException("image has a Raster");
|
||||||
@@ -137,7 +148,7 @@ public final class ICNSImageWriter extends ImageWriterBase {
|
|||||||
imageOutput.writeInt(IconResource.typeFromImage(image.getRenderedImage(), "PNG"));
|
imageOutput.writeInt(IconResource.typeFromImage(image.getRenderedImage(), "PNG"));
|
||||||
imageOutput.writeInt(0); // Size, update later
|
imageOutput.writeInt(0); // Size, update later
|
||||||
|
|
||||||
processImageStarted(imageIndex);
|
processImageStarted(sequenceIndex);
|
||||||
|
|
||||||
// Write icon in PNG format
|
// Write icon in PNG format
|
||||||
ImageWriter writer = getPNGDelegate();
|
ImageWriter writer = getPNGDelegate();
|
||||||
@@ -197,7 +208,7 @@ public final class ICNSImageWriter extends ImageWriterBase {
|
|||||||
pngDelegate.addIIOWriteWarningListener(new IIOWriteWarningListener() {
|
pngDelegate.addIIOWriteWarningListener(new IIOWriteWarningListener() {
|
||||||
@Override
|
@Override
|
||||||
public void warningOccurred(ImageWriter source, int imageIndex, String warning) {
|
public void warningOccurred(ImageWriter source, int imageIndex, String warning) {
|
||||||
processWarningOccurred(sequence.current(), warning);
|
processWarningOccurred(sequenceIndex, warning);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-iff</artifactId>
|
<artifactId>imageio-iff</artifactId>
|
||||||
<name>TwelveMonkeys » ImageIO » IFF plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: IFF plugin</name>
|
||||||
<description>
|
<description>
|
||||||
ImageIO plugin for Amiga/Electronic Arts Interchange File Format (IFF)
|
ImageIO plugin for Amiga/Electronic Arts Interchange File Format (IFF)
|
||||||
type ILBM and PBM format.
|
type ILBM and PBM format.
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-jpeg-jai-interop</artifactId>
|
<artifactId>imageio-jpeg-jai-interop</artifactId>
|
||||||
<name>TwelveMonkeys » ImageIO » JPEG/JAI TIFF Interop</name>
|
<name>TwelveMonkeys :: ImageIO :: JPEG/JAI TIFF Interop</name>
|
||||||
<description>
|
<description>
|
||||||
Test JPEG plugin and JAI TIFF plugin interoperability
|
Test JPEG plugin and JAI TIFF plugin interoperability
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-jpeg-jep262-interop</artifactId>
|
<artifactId>imageio-jpeg-jep262-interop</artifactId>
|
||||||
<name>TwelveMonkeys » ImageIO » JPEG/JEP-262 Interop</name>
|
<name>TwelveMonkeys :: ImageIO :: JPEG/JEP-262 Interop</name>
|
||||||
<description>
|
<description>
|
||||||
Test JPEG plugin and JEP-262 (JDK TIFF plugin) interoperability
|
Test JPEG plugin and JEP-262 (JDK TIFF plugin) interoperability
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-jpeg</artifactId>
|
<artifactId>imageio-jpeg</artifactId>
|
||||||
<name>TwelveMonkeys » ImageIO » JPEG plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: JPEG plugin</name>
|
||||||
<description>
|
<description>
|
||||||
ImageIO plugin for Joint Photographer Expert Group images (JPEG/JFIF).
|
ImageIO plugin for Joint Photographer Expert Group images (JPEG/JFIF).
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
+3
-23
@@ -212,9 +212,7 @@ final class JPEGLosslessDecoder {
|
|||||||
|
|
||||||
final int[] firstValue = new int[numComp];
|
final int[] firstValue = new int[numComp];
|
||||||
for (int i = 0; i < numComp; i++) {
|
for (int i = 0; i < numComp; i++) {
|
||||||
// scan.approxLow is the point transformation (Pt) value
|
firstValue[i] = (1 << (precision - 1));
|
||||||
// ref. ISO/IEC 10918-1 H.1.2.1
|
|
||||||
firstValue[i] = (1 << (precision - scan.approxLow - 1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final int[] pred = new int[numComp];
|
final int[] pred = new int[numComp];
|
||||||
@@ -234,11 +232,6 @@ final class JPEGLosslessDecoder {
|
|||||||
output(pred);
|
output(pred);
|
||||||
current = decode(pred, temp, index);
|
current = decode(pred, temp, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((current == JPEG.EOI) && (xLoc == xDim - 1) && (yLoc == yDim - 1)) {
|
|
||||||
// Output value left in pred if EOI is hit while decoding last pixel
|
|
||||||
output(pred);
|
|
||||||
}
|
|
||||||
|
|
||||||
break; //current=MARKER
|
break; //current=MARKER
|
||||||
}
|
}
|
||||||
@@ -275,17 +268,6 @@ final class JPEGLosslessDecoder {
|
|||||||
// TODO oe: 05.05.2018 Is it correct loop? Content of outputData from previous iteration is always lost.
|
// TODO oe: 05.05.2018 Is it correct loop? Content of outputData from previous iteration is always lost.
|
||||||
} while ((current != JPEG.EOI) && ((xLoc < xDim) && (yLoc < yDim)) && (scanNum == 0));
|
} while ((current != JPEG.EOI) && ((xLoc < xDim) && (yLoc < yDim)) && (scanNum == 0));
|
||||||
|
|
||||||
// Apply point transform to output. This must be done after it has finished being
|
|
||||||
// used for predictive purposes.
|
|
||||||
if (scan.approxLow != 0) {
|
|
||||||
for (int componentIndex = 0; componentIndex < numComp; ++componentIndex) {
|
|
||||||
int[] comp = outputData[componentIndex];
|
|
||||||
for (int i = 0; i < comp.length; i++) {
|
|
||||||
comp[i] = mask & (comp[i] << scan.approxLow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return outputData;
|
return outputData;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,11 +329,9 @@ final class JPEGLosslessDecoder {
|
|||||||
private int decodeSingle(final int[] prev, final int[] temp, final int[] index) throws IOException {
|
private int decodeSingle(final int[] prev, final int[] temp, final int[] index) throws IOException {
|
||||||
// At the beginning of the first line and
|
// At the beginning of the first line and
|
||||||
// at the beginning of each restart interval the prediction value of 2P – 1 is used, where P is the input precision.
|
// at the beginning of each restart interval the prediction value of 2P – 1 is used, where P is the input precision.
|
||||||
// If the point transformation parameter (see A.4) is non-zero, the prediction value at the beginning of the first lines and the
|
|
||||||
// beginning of each restart interval is 2P – Pt – 1 , where Pt is the value of the point transformation parameter
|
|
||||||
if (restarting) {
|
if (restarting) {
|
||||||
restarting = false;
|
restarting = false;
|
||||||
prev[0] = (1 << (frame.samplePrecision - scan.approxLow - 1));
|
prev[0] = (1 << (frame.samplePrecision - 1));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final int[] outputData = this.outputData[0];
|
final int[] outputData = this.outputData[0];
|
||||||
@@ -706,7 +686,7 @@ final class JPEGLosslessDecoder {
|
|||||||
return getPreviousY(data);
|
return getPreviousY(data);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return (1 << (frame.samplePrecision - scan.approxLow - 1));
|
return (1 << (frame.samplePrecision - 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-61
@@ -2033,65 +2033,4 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReadLosslessJPEGGradient() throws IOException {
|
|
||||||
JPEGImageReader reader = createReader();
|
|
||||||
|
|
||||||
try (ImageInputStream stream = ImageIO.createImageInputStream(getClassLoaderResource("/jpeg-lossless/gradient_ls.jpg"))) {
|
|
||||||
reader.setInput(stream);
|
|
||||||
|
|
||||||
assertEquals(256, reader.getWidth(0));
|
|
||||||
assertEquals(256, reader.getHeight(0));
|
|
||||||
|
|
||||||
BufferedImage image = reader.read(0, null);
|
|
||||||
|
|
||||||
assertNotNull(image);
|
|
||||||
assertEquals(256, image.getWidth());
|
|
||||||
assertEquals(256, image.getHeight());
|
|
||||||
assertEquals(16, image.getColorModel().getComponentSize(0));
|
|
||||||
|
|
||||||
for (int y = 0; y < 256; y++) {
|
|
||||||
for (int x = 0; x < 256; x++) {
|
|
||||||
assertEquals((y << 8) | x, image.getRaster().getSample(x, y, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
reader.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReadLosslessJPEGGradientWithPointTransform() throws IOException {
|
|
||||||
JPEGImageReader reader = createReader();
|
|
||||||
|
|
||||||
try (ImageInputStream stream = ImageIO.createImageInputStream(getClassLoaderResource("/jpeg-lossless/gradient_ls_pt.jpg"))) {
|
|
||||||
reader.setInput(stream);
|
|
||||||
|
|
||||||
assertEquals(256, reader.getWidth(0));
|
|
||||||
assertEquals(256, reader.getHeight(0));
|
|
||||||
|
|
||||||
BufferedImage image = reader.read(0, null);
|
|
||||||
|
|
||||||
assertNotNull(image);
|
|
||||||
assertEquals(256, image.getWidth());
|
|
||||||
assertEquals(256, image.getHeight());
|
|
||||||
assertEquals(16, image.getColorModel().getComponentSize(0));
|
|
||||||
|
|
||||||
for (int y = 0; y < 256; y++) {
|
|
||||||
for (int x = 0; x < 256; x++) {
|
|
||||||
int expected = (y << 8) | x;
|
|
||||||
|
|
||||||
// Simulate effect of precision loss due to point transform = 4
|
|
||||||
expected = (expected >> 4) << 4;
|
|
||||||
|
|
||||||
assertEquals(expected, image.getRaster().getSample(x, y, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
reader.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 9.2 KiB |
@@ -3,11 +3,11 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>imageio-metadata</artifactId>
|
<artifactId>imageio-metadata</artifactId>
|
||||||
<name>TwelveMonkeys » ImageIO » Metadata</name>
|
<name>TwelveMonkeys :: ImageIO :: Metadata</name>
|
||||||
<description>
|
<description>
|
||||||
TwelveMonkeys ImageIO metadata support classes.
|
TwelveMonkeys ImageIO metadata support classes.
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
+2
-6
@@ -41,11 +41,7 @@ import javax.imageio.stream.ImageOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static com.twelvemonkeys.imageio.metadata.tiff.TIFFEntry.getType;
|
import static com.twelvemonkeys.imageio.metadata.tiff.TIFFEntry.getType;
|
||||||
import static com.twelvemonkeys.imageio.metadata.tiff.TIFFEntry.getValueLength;
|
import static com.twelvemonkeys.imageio.metadata.tiff.TIFFEntry.getValueLength;
|
||||||
@@ -180,7 +176,7 @@ public final class TIFFWriter extends MetadataWriter {
|
|||||||
stream.seek(dataOffset);
|
stream.seek(dataOffset);
|
||||||
Directory subIFD = (Directory) value;
|
Directory subIFD = (Directory) value;
|
||||||
writeIFD(subIFD, stream, true);
|
writeIFD(subIFD, stream, true);
|
||||||
dataOffset += computeDataSize(subIFD) + directoryCountLength + subIFD.size() * entryLength;
|
dataOffset += computeDataSize(subIFD);
|
||||||
stream.seek(streamPosition);
|
stream.seek(streamPosition);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
+10
-64
@@ -30,23 +30,14 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.metadata.tiff;
|
package com.twelvemonkeys.imageio.metadata.tiff;
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.metadata.AbstractDirectory;
|
import com.twelvemonkeys.imageio.metadata.*;
|
||||||
import com.twelvemonkeys.imageio.metadata.AbstractEntry;
|
|
||||||
import com.twelvemonkeys.imageio.metadata.CompoundDirectory;
|
|
||||||
import com.twelvemonkeys.imageio.metadata.Directory;
|
|
||||||
import com.twelvemonkeys.imageio.metadata.Entry;
|
|
||||||
import com.twelvemonkeys.imageio.metadata.MetadataWriterAbstractTest;
|
|
||||||
import com.twelvemonkeys.imageio.metadata.exif.EXIF;
|
|
||||||
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
||||||
import com.twelvemonkeys.io.FastByteArrayOutputStream;
|
import com.twelvemonkeys.io.FastByteArrayOutputStream;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
|
||||||
import javax.imageio.stream.ImageOutputStream;
|
import javax.imageio.stream.ImageOutputStream;
|
||||||
import javax.imageio.stream.ImageOutputStreamImpl;
|
import javax.imageio.stream.ImageOutputStreamImpl;
|
||||||
import javax.imageio.stream.MemoryCacheImageOutputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@@ -55,10 +46,8 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
import org.junit.jupiter.api.Test;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TIFFWriterTest
|
* TIFFWriterTest
|
||||||
@@ -283,7 +272,7 @@ public class TIFFWriterTest extends MetadataWriterAbstractTest {
|
|||||||
Directory read = new TIFFReader().read(new ByteArrayImageInputStream(data));
|
Directory read = new TIFFReader().read(new ByteArrayImageInputStream(data));
|
||||||
|
|
||||||
assertNotNull(read.getEntryById(TIFF.TAG_SOFTWARE));
|
assertNotNull(read.getEntryById(TIFF.TAG_SOFTWARE));
|
||||||
assertInstanceOf(String[].class, read.getEntryById(TIFF.TAG_SOFTWARE).getValue(), "value not an string array");
|
assertTrue(read.getEntryById(TIFF.TAG_SOFTWARE).getValue() instanceof String[], "value not an string array");
|
||||||
assertArrayEquals(strings, (String[]) read.getEntryById(TIFF.TAG_SOFTWARE).getValue());
|
assertArrayEquals(strings, (String[]) read.getEntryById(TIFF.TAG_SOFTWARE).getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -296,7 +285,7 @@ public class TIFFWriterTest extends MetadataWriterAbstractTest {
|
|||||||
TIFFEntry subSubIFD = new TIFFEntry(TIFF.TAG_SUB_IFD, TIFF.TYPE_LONG, new IFD(Collections.singletonList(subSubSubIFD)));
|
TIFFEntry subSubIFD = new TIFFEntry(TIFF.TAG_SUB_IFD, TIFF.TYPE_LONG, new IFD(Collections.singletonList(subSubSubIFD)));
|
||||||
TIFFEntry subIFD = new TIFFEntry(TIFF.TAG_SUB_IFD, TIFF.TYPE_LONG, new IFD(Collections.singletonList(subSubIFD)));
|
TIFFEntry subIFD = new TIFFEntry(TIFF.TAG_SUB_IFD, TIFF.TYPE_LONG, new IFD(Collections.singletonList(subSubIFD)));
|
||||||
|
|
||||||
List<Entry> entries = Collections.singletonList(subIFD);
|
List<Entry> entries = Collections.<Entry>singletonList(subIFD);
|
||||||
|
|
||||||
TIFFWriter writer = createWriter();
|
TIFFWriter writer = createWriter();
|
||||||
|
|
||||||
@@ -307,67 +296,24 @@ public class TIFFWriterTest extends MetadataWriterAbstractTest {
|
|||||||
assertEquals(96, stream.getStreamPosition()); // 96 = 4 + 5 * (2 + 12) + 22
|
assertEquals(96, stream.getStreamPosition()); // 96 = 4 + 5 * (2 + 12) + 22
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
private static class NullImageOutputStream extends ImageOutputStreamImpl {
|
||||||
void testWriteNestedExifIFD() throws IOException {
|
|
||||||
String expectedUserComment = "This ia the expected user comment";
|
|
||||||
String expectedDateTime = "2026:01:01 00:00:01";
|
|
||||||
|
|
||||||
List<Entry> entries = new ArrayList<>();
|
|
||||||
List<Entry> subDirectoryEntries = new ArrayList<>();
|
|
||||||
subDirectoryEntries.add(new TIFFEntry(EXIF.TAG_USER_COMMENT, TIFF.TYPE_ASCII, expectedUserComment));
|
|
||||||
entries.add(new TIFFEntry(TIFF.TAG_DATE_TIME, expectedDateTime));
|
|
||||||
entries.add(new TIFFEntry(TIFF.TAG_EXIF_IFD, TIFF.TYPE_IFD, new IFD(subDirectoryEntries)));
|
|
||||||
// NOTE! For the test, it is important that this tag is > Exif IFD and inside IDF0 (even if this is an Exif tag)
|
|
||||||
entries.add(new TIFFEntry(EXIF.TAG_DATE_TIME_ORIGINAL, TIFF.TYPE_ASCII, expectedDateTime));
|
|
||||||
|
|
||||||
IFD expectedSub = new IFD(subDirectoryEntries);
|
|
||||||
IFD expected = new IFD(entries);
|
|
||||||
|
|
||||||
try (ByteArrayOutputStream bytes = new ByteArrayOutputStream()) {
|
|
||||||
// Write the TIFF w/Exif sub IFD
|
|
||||||
try (ImageOutputStream stream = new MemoryCacheImageOutputStream(bytes)) {
|
|
||||||
new TIFFWriter().write(expected, stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
try (ImageInputStream stream = new ByteArrayImageInputStream(bytes.toByteArray())) {
|
|
||||||
// Read the TIFF back, and compare content
|
|
||||||
Directory directory = new TIFFReader().read(stream);
|
|
||||||
|
|
||||||
Entry dateTimeEntry = directory.getEntryById(EXIF.TAG_DATE_TIME_ORIGINAL);
|
|
||||||
assertNotNull(dateTimeEntry);
|
|
||||||
assertEquals(expectedDateTime, dateTimeEntry.getValue());
|
|
||||||
|
|
||||||
Entry exifEntry = directory.getEntryById(TIFF.TAG_EXIF_IFD);
|
|
||||||
IFD exifIFD = (IFD) exifEntry.getValue();
|
|
||||||
|
|
||||||
Entry userCommentEntry = exifIFD.getEntryById(EXIF.TAG_USER_COMMENT);
|
|
||||||
assertNotNull(userCommentEntry);
|
|
||||||
|
|
||||||
assertEquals(expectedUserComment, userCommentEntry.getValue());
|
|
||||||
assertEquals(expectedSub, exifIFD);
|
|
||||||
assertEquals(expected, ((CompoundDirectory) directory).getDirectory(0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class NullImageOutputStream extends ImageOutputStreamImpl {
|
|
||||||
@Override
|
@Override
|
||||||
public void write(int b) {
|
public void write(int b) throws IOException {
|
||||||
streamPos++;
|
streamPos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(byte[] b, int off, int len) {
|
public void write(byte[] b, int off, int len) throws IOException {
|
||||||
streamPos += len;
|
streamPos += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int read() {
|
public int read() throws IOException {
|
||||||
throw new UnsupportedOperationException("Method read not implemented");
|
throw new UnsupportedOperationException("Method read not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int read(byte[] b, int off, int len) {
|
public int read(byte[] b, int off, int len) throws IOException {
|
||||||
throw new UnsupportedOperationException("Method read not implemented");
|
throw new UnsupportedOperationException("Method read not implemented");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-pcx</artifactId>
|
<artifactId>imageio-pcx</artifactId>
|
||||||
<name>TwelveMonkeys » ImageIO » PCX plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: PCX plugin</name>
|
||||||
<description>
|
<description>
|
||||||
ImageIO plugin for ZSoft Paintbrush Format (PCX)
|
ImageIO plugin for ZSoft Paintbrush Format (PCX)
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-pdf</artifactId>
|
<artifactId>imageio-pdf</artifactId>
|
||||||
<name>TwelveMonkeys » ImageIO » PDF plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: PDF plugin</name>
|
||||||
<description>
|
<description>
|
||||||
ImageIO plugin for Adobe Portable Document Format (PDF).
|
ImageIO plugin for Adobe Portable Document Format (PDF).
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-pict</artifactId>
|
<artifactId>imageio-pict</artifactId>
|
||||||
<name>TwelveMonkeys » ImageIO » PICT plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: PICT plugin</name>
|
||||||
<description>ImageIO plugin for Apple Mac Paint Picture (PICT) format.</description>
|
<description>ImageIO plugin for Apple Mac Paint Picture (PICT) format.</description>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-pnm</artifactId>
|
<artifactId>imageio-pnm</artifactId>
|
||||||
<name>TwelveMonkeys » ImageIO » PNM plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: PNM plugin</name>
|
||||||
<description>
|
<description>
|
||||||
ImageIO plugin for NetPBM Portable Any Map (PNM)
|
ImageIO plugin for NetPBM Portable Any Map (PNM)
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
+1
-6
@@ -111,7 +111,6 @@ enum TupleType {
|
|||||||
|
|
||||||
static TupleType forPAM(Raster raster) {
|
static TupleType forPAM(Raster raster) {
|
||||||
SampleModel sampleModel = raster.getSampleModel();
|
SampleModel sampleModel = raster.getSampleModel();
|
||||||
|
|
||||||
switch (sampleModel.getTransferType()) {
|
switch (sampleModel.getTransferType()) {
|
||||||
case DataBuffer.TYPE_BYTE:
|
case DataBuffer.TYPE_BYTE:
|
||||||
case DataBuffer.TYPE_USHORT:
|
case DataBuffer.TYPE_USHORT:
|
||||||
@@ -146,12 +145,8 @@ enum TupleType {
|
|||||||
return TupleType.RGB;
|
return TupleType.RGB;
|
||||||
}
|
}
|
||||||
else if (bands == 4) {
|
else if (bands == 4) {
|
||||||
// Ambiguous, could also be CMYK...
|
|
||||||
return TupleType.RGB_ALPHA;
|
return TupleType.RGB_ALPHA;
|
||||||
}
|
}
|
||||||
else if (bands == 5) {
|
|
||||||
return TupleType.CMYK_ALPHA;
|
|
||||||
}
|
|
||||||
// ...else fall through...
|
// ...else fall through...
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +154,7 @@ enum TupleType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static TupleType forPAM(ImageTypeSpecifier type) {
|
static TupleType forPAM(ImageTypeSpecifier type) {
|
||||||
// Support only 1 bit b/w, 8-16 bit gray, 8-16 bit/sample RGB and 8-16 bit/sample CMYK
|
// Support only 1 bit b/w, 8-16 bit gray and 8-16 bit/sample RGB
|
||||||
switch (type.getBufferedImageType()) {
|
switch (type.getBufferedImageType()) {
|
||||||
// 1 bit b/w or b/w + a
|
// 1 bit b/w or b/w + a
|
||||||
case BufferedImage.TYPE_BYTE_BINARY:
|
case BufferedImage.TYPE_BYTE_BINARY:
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-psd</artifactId>
|
<artifactId>imageio-psd</artifactId>
|
||||||
<name>TwelveMonkeys » ImageIO » PSD plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: PSD plugin</name>
|
||||||
<description>
|
<description>
|
||||||
ImageIO plugin for Adobe Photoshop Document (PSD).
|
ImageIO plugin for Adobe Photoshop Document (PSD).
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
+3
-3
@@ -410,9 +410,9 @@ public final class PSDMetadata extends AbstractMetadata {
|
|||||||
if ((psdLayerInfo.blendMode.flags & 0x01) != 0) {
|
if ((psdLayerInfo.blendMode.flags & 0x01) != 0) {
|
||||||
node.setAttribute("transparencyProtected", "true");
|
node.setAttribute("transparencyProtected", "true");
|
||||||
}
|
}
|
||||||
// Include always, to avoid ambiguity, as the flag is really "hidden", not "visible"...
|
if ((psdLayerInfo.blendMode.flags & 0x02) != 0) {
|
||||||
boolean hidden = (psdLayerInfo.blendMode.flags & 0x02) != 0;
|
node.setAttribute("visible", "true");
|
||||||
node.setAttribute("visible", hidden ? "false" : "true");
|
}
|
||||||
if ((psdLayerInfo.blendMode.flags & 0x04) != 0) {
|
if ((psdLayerInfo.blendMode.flags & 0x04) != 0) {
|
||||||
node.setAttribute("obsolete", "true");
|
node.setAttribute("obsolete", "true");
|
||||||
}
|
}
|
||||||
|
|||||||
-119
@@ -1,119 +0,0 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.psd;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URL;
|
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import javax.imageio.metadata.IIOMetadata;
|
|
||||||
import javax.imageio.metadata.IIOMetadataNode;
|
|
||||||
import javax.imageio.spi.IIORegistry;
|
|
||||||
import javax.imageio.spi.ImageReaderSpi;
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import org.w3c.dom.NodeList;
|
|
||||||
|
|
||||||
import com.twelvemonkeys.imageio.stream.URLImageInputStreamSpi;
|
|
||||||
|
|
||||||
class PSDMetadataTest {
|
|
||||||
static {
|
|
||||||
IIORegistry.getDefaultInstance().registerServiceProvider(new URLImageInputStreamSpi());
|
|
||||||
ImageIO.setUseCache(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final PSDImageReaderSpi provider = createProvider();
|
|
||||||
|
|
||||||
private PSDImageReaderSpi createProvider() {
|
|
||||||
return new PSDImageReaderSpi();
|
|
||||||
}
|
|
||||||
|
|
||||||
private PSDImageReader createReader() throws IOException {
|
|
||||||
return (PSDImageReader) provider.createReaderInstance(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected URL getClassLoaderResource(final String resource) {
|
|
||||||
return getClass().getResource(resource);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void testLayerInfo() throws IOException {
|
|
||||||
PSDImageReader imageReader = createReader();
|
|
||||||
|
|
||||||
try (ImageInputStream stream = ImageIO.createImageInputStream(getClassLoaderResource("/psd/photoshopping.psd"))) {
|
|
||||||
imageReader.setInput(stream);
|
|
||||||
|
|
||||||
IIOMetadata metadata = imageReader.getImageMetadata(0);
|
|
||||||
IIOMetadataNode root = (IIOMetadataNode) metadata.getAsTree(PSDMetadata.NATIVE_METADATA_FORMAT_NAME);
|
|
||||||
NodeList layerInfos = root.getElementsByTagName("LayerInfo");
|
|
||||||
|
|
||||||
assertEquals(5, layerInfos.getLength()); // Sanity
|
|
||||||
|
|
||||||
IIOMetadataNode layer1Info = (IIOMetadataNode) layerInfos.item(0);
|
|
||||||
assertEquals("Layer 1", layer1Info.getAttribute("name"));
|
|
||||||
assertEquals("2", layer1Info.getAttribute("layerId"));
|
|
||||||
assertEquals("0", layer1Info.getAttribute("top"));
|
|
||||||
assertEquals("0", layer1Info.getAttribute("left"));
|
|
||||||
assertEquals("225", layer1Info.getAttribute("bottom"));
|
|
||||||
assertEquals("300", layer1Info.getAttribute("right"));
|
|
||||||
assertEquals("norm", layer1Info.getAttribute("blendMode"));
|
|
||||||
assertEquals("255", layer1Info.getAttribute("opacity"));
|
|
||||||
assertEquals("base", layer1Info.getAttribute("clipping"));
|
|
||||||
assertEquals("true", layer1Info.getAttribute("visible"));
|
|
||||||
assertEquals("8", layer1Info.getAttribute("flags"));
|
|
||||||
|
|
||||||
IIOMetadataNode layer2Info = (IIOMetadataNode) layerInfos.item(1);
|
|
||||||
assertEquals("Layer 0 copy", layer2Info.getAttribute("name"));
|
|
||||||
assertEquals("11", layer2Info.getAttribute("layerId"));
|
|
||||||
assertEquals("0", layer2Info.getAttribute("top"));
|
|
||||||
assertEquals("0", layer2Info.getAttribute("left"));
|
|
||||||
assertEquals("225", layer2Info.getAttribute("bottom"));
|
|
||||||
assertEquals("300", layer2Info.getAttribute("right"));
|
|
||||||
assertEquals("norm", layer2Info.getAttribute("blendMode"));
|
|
||||||
assertEquals("255", layer2Info.getAttribute("opacity"));
|
|
||||||
assertEquals("base", layer2Info.getAttribute("clipping"));
|
|
||||||
assertEquals("true", layer2Info.getAttribute("visible"));
|
|
||||||
assertEquals("8", layer2Info.getAttribute("flags"));
|
|
||||||
|
|
||||||
IIOMetadataNode layer3Info = (IIOMetadataNode) layerInfos.item(2);
|
|
||||||
assertEquals("Layer 0 copy 2", layer3Info.getAttribute("name"));
|
|
||||||
assertEquals("12", layer3Info.getAttribute("layerId"));
|
|
||||||
assertEquals("0", layer3Info.getAttribute("top"));
|
|
||||||
assertEquals("0", layer3Info.getAttribute("left"));
|
|
||||||
assertEquals("225", layer3Info.getAttribute("bottom"));
|
|
||||||
assertEquals("159", layer3Info.getAttribute("right"));
|
|
||||||
assertEquals("norm", layer3Info.getAttribute("blendMode"));
|
|
||||||
assertEquals("255", layer3Info.getAttribute("opacity"));
|
|
||||||
assertEquals("base", layer3Info.getAttribute("clipping"));
|
|
||||||
assertEquals("true", layer3Info.getAttribute("visible"));
|
|
||||||
assertEquals("8", layer3Info.getAttribute("flags"));
|
|
||||||
|
|
||||||
IIOMetadataNode layer4Info = (IIOMetadataNode) layerInfos.item(3);
|
|
||||||
assertEquals("Layer 0 copy 3", layer4Info.getAttribute("name"));
|
|
||||||
assertEquals("13", layer4Info.getAttribute("layerId"));
|
|
||||||
assertEquals("0", layer4Info.getAttribute("top"));
|
|
||||||
assertEquals("0", layer4Info.getAttribute("left"));
|
|
||||||
assertEquals("225", layer4Info.getAttribute("bottom"));
|
|
||||||
assertEquals("300", layer4Info.getAttribute("right"));
|
|
||||||
assertEquals("norm", layer4Info.getAttribute("blendMode"));
|
|
||||||
assertEquals("255", layer4Info.getAttribute("opacity"));
|
|
||||||
assertEquals("base", layer4Info.getAttribute("clipping"));
|
|
||||||
assertEquals("false", layer4Info.getAttribute("visible"));
|
|
||||||
assertEquals("10", layer4Info.getAttribute("flags"));
|
|
||||||
|
|
||||||
IIOMetadataNode layer5Info = (IIOMetadataNode) layerInfos.item(4);
|
|
||||||
assertEquals("Layer 0", layer5Info.getAttribute("name"));
|
|
||||||
assertEquals("3", layer5Info.getAttribute("layerId"));
|
|
||||||
assertEquals("0", layer5Info.getAttribute("top"));
|
|
||||||
assertEquals("0", layer5Info.getAttribute("left"));
|
|
||||||
assertEquals("225", layer5Info.getAttribute("bottom"));
|
|
||||||
assertEquals("300", layer5Info.getAttribute("right"));
|
|
||||||
assertEquals("norm", layer5Info.getAttribute("blendMode"));
|
|
||||||
assertEquals("255", layer5Info.getAttribute("opacity"));
|
|
||||||
assertEquals("base", layer5Info.getAttribute("clipping"));
|
|
||||||
assertEquals("false", layer5Info.getAttribute("visible"));
|
|
||||||
assertEquals("10", layer5Info.getAttribute("flags"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,10 +4,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-reference</artifactId>
|
<artifactId>imageio-reference</artifactId>
|
||||||
<name>TwelveMonkeys » ImageIO » JDK Reference Tests</name>
|
<name>TwelveMonkeys :: ImageIO :: JDK Reference Tests</name>
|
||||||
<description>
|
<description>
|
||||||
Test cases for the JRE provided ImageReader implementations for reference.
|
Test cases for the JRE provided ImageReader implementations for reference.
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
-6
@@ -111,12 +111,6 @@ public class JPEGImageReaderTest extends ImageReaderAbstractTest<JPEGImageReader
|
|||||||
super.testReadAsRenderedImageIndexOutOfBounds();
|
super.testReadAsRenderedImageIndexOutOfBounds();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
@Disabled("JDK 25 now supports reading Exif thumbnails, but does not report thumbnail progress")
|
|
||||||
public void testThumbnailProgress() throws IOException {
|
|
||||||
super.testThumbnailProgress();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Disabled("No test data with JFIF thumbnail")
|
@Disabled("No test data with JFIF thumbnail")
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-sgi</artifactId>
|
<artifactId>imageio-sgi</artifactId>
|
||||||
<name>TwelveMonkeys » ImageIO » SGI plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: SGI plugin</name>
|
||||||
<description>
|
<description>
|
||||||
ImageIO plugin for Silicon Graphics Image Format (SGI)
|
ImageIO plugin for Silicon Graphics Image Format (SGI)
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-tga</artifactId>
|
<artifactId>imageio-tga</artifactId>
|
||||||
<name>TwelveMonkeys » ImageIO » TGA plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: TGA plugin</name>
|
||||||
<description>
|
<description>
|
||||||
ImageIO plugin for Truevision TGA Image Format (TGA)
|
ImageIO plugin for Truevision TGA Image Format (TGA)
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-thumbsdb</artifactId>
|
<artifactId>imageio-thumbsdb</artifactId>
|
||||||
<name>TwelveMonkeys » ImageIO » Thumbs.db plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: Thumbs.db plugin</name>
|
||||||
<description>
|
<description>
|
||||||
ImageIO plugin for Windows Thumbs DB (Thumbs.db) format.
|
ImageIO plugin for Windows Thumbs DB (Thumbs.db) format.
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-tiff-jai-interop</artifactId>
|
<artifactId>imageio-tiff-jai-interop</artifactId>
|
||||||
<name>TwelveMonkeys » ImageIO » TIFF/JAI Metadata Interop</name>
|
<name>TwelveMonkeys :: ImageIO :: TIFF/JAI Metadata Interop</name>
|
||||||
<description>
|
<description>
|
||||||
Test TIFF plugin and JAI TIFF plugin Metadata interoperability
|
Test TIFF plugin and JAI TIFF plugin Metadata interoperability
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-tiff-jdk-interop</artifactId>
|
<artifactId>imageio-tiff-jdk-interop</artifactId>
|
||||||
<name>TwelveMonkeys » ImageIO » TIFF/JDK JPEG Interop</name>
|
<name>TwelveMonkeys :: ImageIO :: TIFF/JDK JPEG Interop</name>
|
||||||
<description>
|
<description>
|
||||||
Test TIFF plugin and JDK JPEG plugin interoperability
|
Test TIFF plugin and JDK JPEG plugin interoperability
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-tiff</artifactId>
|
<artifactId>imageio-tiff</artifactId>
|
||||||
<name>TwelveMonkeys » ImageIO » TIFF plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: TIFF plugin</name>
|
||||||
<description>
|
<description>
|
||||||
ImageIO plugin for Aldus/Adobe Tagged Image File Format (TIFF).
|
ImageIO plugin for Aldus/Adobe Tagged Image File Format (TIFF).
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
+7
-4
@@ -71,16 +71,18 @@ public final class TIFFImageMetadata extends AbstractMetadata {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an empty TIFF metadata object.
|
* Creates an empty TIFF metadata object.
|
||||||
|
*
|
||||||
* Client code can update or change the metadata using the
|
* Client code can update or change the metadata using the
|
||||||
* {@link #setFromTree(String, Node)}
|
* {@link #setFromTree(String, Node)}
|
||||||
* or {@link #mergeTree(String, Node)} methods.
|
* or {@link #mergeTree(String, Node)} methods.
|
||||||
*/
|
*/
|
||||||
public TIFFImageMetadata() {
|
public TIFFImageMetadata() {
|
||||||
this(new IFD(Collections.emptyList()));
|
this(new IFD(Collections.<Entry>emptyList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a TIFF metadata object, using the values from the given IFD.
|
* Creates a TIFF metadata object, using the values from the given IFD.
|
||||||
|
*
|
||||||
* Client code can update or change the metadata using the
|
* Client code can update or change the metadata using the
|
||||||
* {@link #setFromTree(String, Node)}
|
* {@link #setFromTree(String, Node)}
|
||||||
* or {@link #mergeTree(String, Node)} methods.
|
* or {@link #mergeTree(String, Node)} methods.
|
||||||
@@ -93,6 +95,7 @@ public final class TIFFImageMetadata extends AbstractMetadata {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a TIFF metadata object, using the values from the given entries.
|
* Creates a TIFF metadata object, using the values from the given entries.
|
||||||
|
*
|
||||||
* Client code can update or change the metadata using the
|
* Client code can update or change the metadata using the
|
||||||
* {@link #setFromTree(String, Node)}
|
* {@link #setFromTree(String, Node)}
|
||||||
* or {@link #mergeTree(String, Node)} methods.
|
* or {@link #mergeTree(String, Node)} methods.
|
||||||
@@ -490,10 +493,10 @@ public final class TIFFImageMetadata extends AbstractMetadata {
|
|||||||
compressionTypeName.setAttribute("value", "CCITT RLE");
|
compressionTypeName.setAttribute("value", "CCITT RLE");
|
||||||
break;
|
break;
|
||||||
case TIFFExtension.COMPRESSION_CCITT_T4:
|
case TIFFExtension.COMPRESSION_CCITT_T4:
|
||||||
compressionTypeName.setAttribute("value", "CCITT T.4");
|
compressionTypeName.setAttribute("value", "CCITT T4");
|
||||||
break;
|
break;
|
||||||
case TIFFExtension.COMPRESSION_CCITT_T6:
|
case TIFFExtension.COMPRESSION_CCITT_T6:
|
||||||
compressionTypeName.setAttribute("value", "CCITT T.6");
|
compressionTypeName.setAttribute("value", "CCITT T6");
|
||||||
break;
|
break;
|
||||||
case TIFFExtension.COMPRESSION_LZW:
|
case TIFFExtension.COMPRESSION_LZW:
|
||||||
compressionTypeName.setAttribute("value", "LZW");
|
compressionTypeName.setAttribute("value", "LZW");
|
||||||
@@ -1035,7 +1038,7 @@ public final class TIFFImageMetadata extends AbstractMetadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we have resolution
|
// If we have resolution
|
||||||
if (xRes != null) { // yRes != null too
|
if (xRes != null && yRes != null) {
|
||||||
// If old unit was DPI, convert values and keep DPI, otherwise use PPCM
|
// If old unit was DPI, convert values and keep DPI, otherwise use PPCM
|
||||||
Entry resUnitEntry = entries.get(TIFF.TAG_RESOLUTION_UNIT);
|
Entry resUnitEntry = entries.get(TIFF.TAG_RESOLUTION_UNIT);
|
||||||
int resUnitValue = resUnitEntry != null && resUnitEntry.getValue() != null
|
int resUnitValue = resUnitEntry != null && resUnitEntry.getValue() != null
|
||||||
|
|||||||
+23
-9
@@ -42,7 +42,6 @@ import com.twelvemonkeys.imageio.stream.SubImageOutputStream;
|
|||||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||||
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
||||||
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
||||||
import com.twelvemonkeys.imageio.util.SequenceSupport;
|
|
||||||
import com.twelvemonkeys.io.enc.EncoderStream;
|
import com.twelvemonkeys.io.enc.EncoderStream;
|
||||||
import com.twelvemonkeys.io.enc.PackBitsEncoder;
|
import com.twelvemonkeys.io.enc.PackBitsEncoder;
|
||||||
import com.twelvemonkeys.lang.Validate;
|
import com.twelvemonkeys.lang.Validate;
|
||||||
@@ -111,7 +110,12 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
// Support storing multiple images in one stream (multi-page TIFF)
|
// Support storing multiple images in one stream (multi-page TIFF)
|
||||||
// Support more of the ImageIO metadata (ie. compression from metadata, etc)
|
// Support more of the ImageIO metadata (ie. compression from metadata, etc)
|
||||||
|
|
||||||
private final SequenceSupport sequence = new SequenceSupport();
|
/**
|
||||||
|
* Flag for active sequence writing
|
||||||
|
*/
|
||||||
|
private boolean writingSequence = false;
|
||||||
|
|
||||||
|
private int sequenceIndex = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Metadata writer for sequence writing
|
* Metadata writer for sequence writing
|
||||||
@@ -747,7 +751,7 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
ifd = ((TIFFImageMetadata) inData).getIFD();
|
ifd = ((TIFFImageMetadata) inData).getIFD();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
TIFFImageMetadata outData = new TIFFImageMetadata(Collections.emptySet());
|
TIFFImageMetadata outData = new TIFFImageMetadata(Collections.<Entry>emptySet());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (Arrays.asList(inData.getMetadataFormatNames()).contains(SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME)) {
|
if (Arrays.asList(inData.getMetadataFormatNames()).contains(SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME)) {
|
||||||
@@ -762,7 +766,7 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IIOInvalidTreeException e) {
|
catch (IIOInvalidTreeException e) {
|
||||||
processWarningOccurred(sequence.current(), "Could not convert image meta data: " + e.getMessage());
|
processWarningOccurred(sequenceIndex, "Could not convert image meta data: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
ifd = outData.getIFD();
|
ifd = outData.getIFD();
|
||||||
@@ -962,11 +966,14 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void prepareWriteSequence(final IIOMetadata streamMetadata) throws IOException {
|
public void prepareWriteSequence(final IIOMetadata streamMetadata) throws IOException {
|
||||||
sequence.start();
|
if (writingSequence) {
|
||||||
|
throw new IllegalStateException("sequence writing has already been started!");
|
||||||
|
}
|
||||||
|
|
||||||
assertOutput();
|
assertOutput();
|
||||||
configureStreamByteOrder(streamMetadata, imageOutput);
|
configureStreamByteOrder(streamMetadata, imageOutput);
|
||||||
|
|
||||||
|
writingSequence = true;
|
||||||
sequenceTIFFWriter = new TIFFWriter(isBigTIFF() ? 8 : 4);
|
sequenceTIFFWriter = new TIFFWriter(isBigTIFF() ? 8 : 4);
|
||||||
sequenceTIFFWriter.writeTIFFHeader(imageOutput);
|
sequenceTIFFWriter.writeTIFFHeader(imageOutput);
|
||||||
sequenceLastIFDPos = imageOutput.getStreamPosition();
|
sequenceLastIFDPos = imageOutput.getStreamPosition();
|
||||||
@@ -978,20 +985,26 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeToSequence(final IIOImage image, final ImageWriteParam param) throws IOException {
|
public void writeToSequence(final IIOImage image, final ImageWriteParam param) throws IOException {
|
||||||
int sequenceIndex = sequence.advance();
|
if (!writingSequence) {
|
||||||
|
throw new IllegalStateException("prepareWriteSequence() must be called before writeToSequence()!");
|
||||||
|
}
|
||||||
|
|
||||||
if (sequenceIndex > 0) {
|
if (sequenceIndex > 0) {
|
||||||
imageOutput.flushBefore(sequenceLastIFDPos);
|
imageOutput.flushBefore(sequenceLastIFDPos);
|
||||||
imageOutput.seek(imageOutput.length());
|
imageOutput.seek(imageOutput.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
sequenceLastIFDPos = writePage(sequenceIndex, image, param, sequenceTIFFWriter, sequenceLastIFDPos);
|
sequenceLastIFDPos = writePage(sequenceIndex++, image, param, sequenceTIFFWriter, sequenceLastIFDPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endWriteSequence() throws IOException {
|
public void endWriteSequence() throws IOException {
|
||||||
sequence.end();
|
if (!writingSequence) {
|
||||||
|
throw new IllegalStateException("prepareWriteSequence() must be called before endWriteSequence()!");
|
||||||
|
}
|
||||||
|
|
||||||
|
writingSequence = false;
|
||||||
|
sequenceIndex = 0;
|
||||||
sequenceTIFFWriter = null;
|
sequenceTIFFWriter = null;
|
||||||
sequenceLastIFDPos = -1;
|
sequenceLastIFDPos = -1;
|
||||||
imageOutput.flush();
|
imageOutput.flush();
|
||||||
@@ -1001,7 +1014,8 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
|||||||
protected void resetMembers() {
|
protected void resetMembers() {
|
||||||
super.resetMembers();
|
super.resetMembers();
|
||||||
|
|
||||||
sequence.reset();
|
writingSequence = false;
|
||||||
|
sequenceIndex = 0;
|
||||||
sequenceTIFFWriter = null;
|
sequenceTIFFWriter = null;
|
||||||
sequenceLastIFDPos = -1;
|
sequenceLastIFDPos = -1;
|
||||||
}
|
}
|
||||||
|
|||||||
-96
@@ -188,102 +188,6 @@ public class TIFFImageMetadataTest {
|
|||||||
assertEquals("HP IL v1.1", ((Element) textEntry).getAttribute("value"));
|
assertEquals("HP IL v1.1", ((Element) textEntry).getAttribute("value"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testMetadataStandardFormat_CCITT300dpi() throws IOException {
|
|
||||||
IIOMetadata metadata = createMetadata("/tiff/CCITT-G4-300dpi-StripByteCounts0.tif");
|
|
||||||
Node root = metadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
|
|
||||||
|
|
||||||
// Root: "javax_imageio_1.0"
|
|
||||||
assertNotNull(root);
|
|
||||||
assertEquals(IIOMetadataFormatImpl.standardMetadataFormatName, root.getNodeName());
|
|
||||||
assertEquals(5, root.getChildNodes().getLength());
|
|
||||||
|
|
||||||
// "Chroma"
|
|
||||||
Node chroma = root.getFirstChild();
|
|
||||||
assertEquals("Chroma", chroma.getNodeName());
|
|
||||||
|
|
||||||
assertEquals(3, chroma.getChildNodes().getLength());
|
|
||||||
|
|
||||||
Node colorSpaceType = chroma.getFirstChild();
|
|
||||||
assertEquals("ColorSpaceType", colorSpaceType.getNodeName());
|
|
||||||
assertEquals("GRAY", ((Element) colorSpaceType).getAttribute("name"));
|
|
||||||
|
|
||||||
Node numChannels = colorSpaceType.getNextSibling();
|
|
||||||
assertEquals("NumChannels", numChannels.getNodeName());
|
|
||||||
assertEquals("1", ((Element) numChannels).getAttribute("value"));
|
|
||||||
|
|
||||||
Node blackIsZero = numChannels.getNextSibling();
|
|
||||||
assertEquals("BlackIsZero", blackIsZero.getNodeName());
|
|
||||||
assertEquals("FALSE", ((Element) blackIsZero).getAttribute("value"));
|
|
||||||
|
|
||||||
// "Compression"
|
|
||||||
Node compression = chroma.getNextSibling();
|
|
||||||
assertEquals("Compression", compression.getNodeName());
|
|
||||||
assertEquals(2, compression.getChildNodes().getLength());
|
|
||||||
|
|
||||||
Node compressionTypeName = compression.getFirstChild();
|
|
||||||
assertEquals("CompressionTypeName", compressionTypeName.getNodeName());
|
|
||||||
assertEquals("CCITT T.6", ((Element) compressionTypeName).getAttribute("value"));
|
|
||||||
|
|
||||||
Node lossless = compressionTypeName.getNextSibling();
|
|
||||||
assertEquals("Lossless", lossless.getNodeName());
|
|
||||||
assertEquals(0, lossless.getAttributes().getLength());
|
|
||||||
|
|
||||||
// "Data"
|
|
||||||
Node data = compression.getNextSibling();
|
|
||||||
assertEquals("Data", data.getNodeName());
|
|
||||||
assertEquals(4, data.getChildNodes().getLength());
|
|
||||||
|
|
||||||
Node planarConfiguration = data.getFirstChild();
|
|
||||||
assertEquals("PlanarConfiguration", planarConfiguration.getNodeName());
|
|
||||||
assertEquals("PixelInterleaved", ((Element) planarConfiguration).getAttribute("value"));
|
|
||||||
|
|
||||||
Node sampleFormat = planarConfiguration.getNextSibling();
|
|
||||||
assertEquals("SampleFormat", sampleFormat.getNodeName());
|
|
||||||
assertEquals("UnsignedIntegral", ((Element) sampleFormat).getAttribute("value"));
|
|
||||||
|
|
||||||
Node bitsPerSample = sampleFormat.getNextSibling();
|
|
||||||
assertEquals("BitsPerSample", bitsPerSample.getNodeName());
|
|
||||||
assertEquals("1", ((Element) bitsPerSample).getAttribute("value"));
|
|
||||||
|
|
||||||
Node sampleMSB = bitsPerSample.getNextSibling();
|
|
||||||
assertEquals("SampleMSB", sampleMSB.getNodeName());
|
|
||||||
assertEquals("0", ((Element) sampleMSB).getAttribute("value"));
|
|
||||||
|
|
||||||
// "Dimension"
|
|
||||||
Node dimension = data.getNextSibling();
|
|
||||||
assertEquals("Dimension", dimension.getNodeName());
|
|
||||||
assertEquals(4, dimension.getChildNodes().getLength());
|
|
||||||
|
|
||||||
Node pixelAspectRatio = dimension.getFirstChild();
|
|
||||||
assertEquals("PixelAspectRatio", pixelAspectRatio.getNodeName());
|
|
||||||
assertEquals("1.0", ((Element) pixelAspectRatio).getAttribute("value"));
|
|
||||||
|
|
||||||
Node imageOrientation = pixelAspectRatio.getNextSibling();
|
|
||||||
assertEquals("ImageOrientation", imageOrientation.getNodeName());
|
|
||||||
assertEquals("Normal", ((Element) imageOrientation).getAttribute("value"));
|
|
||||||
|
|
||||||
Node horizontalPixelSize = imageOrientation.getNextSibling();
|
|
||||||
assertEquals("HorizontalPixelSize", horizontalPixelSize.getNodeName());
|
|
||||||
assertEquals("0.08466666666666667", ((Element) horizontalPixelSize).getAttribute("value"));
|
|
||||||
|
|
||||||
Node verticalPixelSize = horizontalPixelSize.getNextSibling();
|
|
||||||
assertEquals("VerticalPixelSize", verticalPixelSize.getNodeName());
|
|
||||||
assertEquals("0.08466666666666667", ((Element) verticalPixelSize).getAttribute("value"));
|
|
||||||
|
|
||||||
// "Document"
|
|
||||||
Node document = dimension.getNextSibling();
|
|
||||||
assertEquals("Document", document.getNodeName());
|
|
||||||
assertEquals(1, document.getChildNodes().getLength());
|
|
||||||
|
|
||||||
Node formatVersion = document.getFirstChild();
|
|
||||||
assertEquals("FormatVersion", formatVersion.getNodeName());
|
|
||||||
assertEquals("6.0", ((Element) formatVersion).getAttribute("value"));
|
|
||||||
|
|
||||||
// No more elements
|
|
||||||
assertNull(document.getNextSibling());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMetadataNativeFormat() throws IOException {
|
public void testMetadataNativeFormat() throws IOException {
|
||||||
IIOMetadata metadata = createMetadata("/tiff/quad-lzw.tif");
|
IIOMetadata metadata = createMetadata("/tiff/quad-lzw.tif");
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||||
<artifactId>imageio</artifactId>
|
<artifactId>imageio</artifactId>
|
||||||
<version>3.13.2-SNAPSHOT</version>
|
<version>3.12.1-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>imageio-webp</artifactId>
|
<artifactId>imageio-webp</artifactId>
|
||||||
<name>TwelveMonkeys » ImageIO » WebP plugin</name>
|
<name>TwelveMonkeys :: ImageIO :: WebP plugin</name>
|
||||||
<description>
|
<description>
|
||||||
ImageIO plugin for Google WebP File Format (WebP).
|
ImageIO plugin for Google WebP File Format (WebP).
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
+1
-1
@@ -565,7 +565,7 @@ final class WebPImageReader extends ImageReaderBase {
|
|||||||
readVP8Lossless(tempRaster, null, width, height);
|
readVP8Lossless(tempRaster, null, width, height);
|
||||||
|
|
||||||
// Copy from green (band 1) in temp to alpha in destination
|
// Copy from green (band 1) in temp to alpha in destination
|
||||||
WritableRaster alphaChannel = tempRaster.createWritableChild(0, 0, width, height, 0, 0, new int[]{1});
|
WritableRaster alphaChannel = tempRaster.createWritableChild(0, 0, tempRaster.getWidth(), tempRaster.getHeight(), 0, 0, new int[]{1});
|
||||||
alphaFilter(alphaChannel, filtering);
|
alphaFilter(alphaChannel, filtering);
|
||||||
copyIntoRasterWithParams(alphaChannel, alphaRaster, param);
|
copyIntoRasterWithParams(alphaChannel, alphaRaster, param);
|
||||||
break;
|
break;
|
||||||
|
|||||||
+41
-49
@@ -166,79 +166,71 @@ final class HuffmanTable {
|
|||||||
if (numPosCodeLens == 1) {
|
if (numPosCodeLens == 1) {
|
||||||
// Length is 0 so mask to clear length bits
|
// Length is 0 so mask to clear length bits
|
||||||
Arrays.fill(level1, lengthsAndSymbols[0] & 0xffff);
|
Arrays.fill(level1, lengthsAndSymbols[0] & 0xffff);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Due to the layout of the elements this effectively first sorts by length and then symbol.
|
// Due to the layout of the elements this effectively first sorts by length and then symbol.
|
||||||
Arrays.sort(lengthsAndSymbols);
|
Arrays.sort(lengthsAndSymbols);
|
||||||
|
|
||||||
int[] count = new int[16];
|
|
||||||
for (int lengthAndSymbol : lengthsAndSymbols) {
|
|
||||||
count[lengthAndSymbol >>> 16]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The next code, in the bit order it would appear on the input stream, i.e. it is reversed.
|
// The next code, in the bit order it would appear on the input stream, i.e. it is reversed.
|
||||||
// Only the lowest bits (corresponding to the bit length of the code) are considered.
|
// Only the lowest bits (corresponding to the bit length of the code) are considered.
|
||||||
// Example: code 0..010 (length 2) would appear as 0..001.
|
// Example: code 0..010 (length 2) would appear as 0..001.
|
||||||
int code = 0;
|
int code = 0;
|
||||||
int step = 2;
|
|
||||||
index = 0;
|
|
||||||
|
|
||||||
for (int length = 1; length <= LEVEL1_BITS; length++, step <<= 1) {
|
// Used for level2 lookup
|
||||||
for (; count[length] > 0; count[length]--) {
|
|
||||||
int lengthAndSymbol = lengthsAndSymbols[index++];
|
|
||||||
|
|
||||||
for (int j = code; j < level1.length; j += step) {
|
|
||||||
level1[j] = lengthAndSymbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
code = nextCode(code, length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int rootMask = (1 << LEVEL1_BITS) - 1;
|
|
||||||
int rootEntry = -1;
|
int rootEntry = -1;
|
||||||
int[] currentTable = null;
|
int[] currentTable = null;
|
||||||
|
|
||||||
step = 2;
|
for (int i = 0; i < lengthsAndSymbols.length; i++) {
|
||||||
for (int length = LEVEL1_BITS + 1; length <= 15; length++, step <<= 1) {
|
int lengthAndSymbol = lengthsAndSymbols[i];
|
||||||
for (; count[length] > 0; count[length]--) {
|
|
||||||
int lengthAndSymbol = lengthsAndSymbols[index++];
|
|
||||||
|
|
||||||
if ((code & rootMask) != rootEntry) {
|
int length = lengthAndSymbol >>> 16;
|
||||||
int level2Bits = nextTableBitSize(count, length, LEVEL1_BITS);
|
|
||||||
int level2Size = 1 << level2Bits;
|
|
||||||
|
|
||||||
currentTable = new int[level2Size];
|
if (length <= LEVEL1_BITS) {
|
||||||
rootEntry = code & rootMask;
|
for (int j = code; j < level1.length; j += 1 << length) {
|
||||||
|
level1[j] = lengthAndSymbol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Existing level2 table not fitting
|
||||||
|
if ((code & ((1 << LEVEL1_BITS) - 1)) != rootEntry) {
|
||||||
|
// Figure out needed table size.
|
||||||
|
// Start at current symbol and length.
|
||||||
|
// Every symbol uses 1 slot at the current bit length.
|
||||||
|
// Going up 1 bit in length multiplies the slots by 2.
|
||||||
|
// No more open slots indicate the table size to be big enough.
|
||||||
|
int maxLength = length;
|
||||||
|
|
||||||
|
for (int j = i, openSlots = 1 << (length - LEVEL1_BITS);
|
||||||
|
j < lengthsAndSymbols.length && openSlots > 0;
|
||||||
|
j++, openSlots--) {
|
||||||
|
|
||||||
|
int innerLength = lengthsAndSymbols[j] >>> 16;
|
||||||
|
|
||||||
|
while (innerLength != maxLength) {
|
||||||
|
maxLength++;
|
||||||
|
openSlots <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int level2Size = maxLength - LEVEL1_BITS;
|
||||||
|
|
||||||
|
currentTable = new int[1 << level2Size];
|
||||||
|
rootEntry = code & ((1 << LEVEL1_BITS) - 1);
|
||||||
level2.add(currentTable);
|
level2.add(currentTable);
|
||||||
|
|
||||||
// Set root table indirection
|
// Set root table indirection
|
||||||
level1[rootEntry] = (LEVEL1_BITS + level2Bits) << 16 | (level2.size() - 1);
|
level1[rootEntry] = (LEVEL1_BITS + level2Size) << 16 | (level2.size() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int value = (length - LEVEL1_BITS) << 16 | (lengthAndSymbol & 0xffff);
|
// Add to existing (or newly generated) 2nd level table
|
||||||
for (int j = (code >>> LEVEL1_BITS); j < currentTable.length; j += step) {
|
for (int j = (code >>> LEVEL1_BITS); j < currentTable.length; j += 1 << (length - LEVEL1_BITS)) {
|
||||||
currentTable[j] = value;
|
currentTable[j] = (length - LEVEL1_BITS) << 16 | (lengthAndSymbol & 0xffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
code = nextCode(code, length);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int nextTableBitSize(int[] count, int length, int rootBits) {
|
code = nextCode(code, length);
|
||||||
int left = 1 << (length - rootBits);
|
|
||||||
while (length < 15) {
|
|
||||||
left -= count[length];
|
|
||||||
if (left <= 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
length++;
|
|
||||||
left <<= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return length - rootBits;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user