mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2026-05-19 00:00:03 -04:00
Compare commits
100 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 92ba91b412 | |||
| c8cb472407 | |||
| 2f56650444 | |||
| ff3d403002 | |||
| ea6070a94e | |||
| 2c7a1d1f91 | |||
| 45ce7aabd8 | |||
| a4d48116ee | |||
| 87729d1558 | |||
| dc322d49dc | |||
| e5a82216d2 | |||
| 5f1e746411 | |||
| 243edc581c | |||
| f982484767 | |||
| e2b18795ca | |||
| bf75cae596 | |||
| b92611151c | |||
| c57ce3dcaf | |||
| 7565a8cbf1 | |||
| 2d25670a7e | |||
| 3d0855c7c6 | |||
| 43216c2045 | |||
| 6152b2b57c | |||
| cbf60c191d | |||
| 32a56cadab | |||
| c796715f0a | |||
| 2494359f42 | |||
| d1f65a2f70 | |||
| b7207f302e | |||
| 9c6d983129 | |||
| e989b4a204 | |||
| aa1568e1a4 | |||
| 84a1800cd1 | |||
| a78faf2b31 | |||
| c5cb54e3e5 | |||
| f492807e71 | |||
| fe382ac89f | |||
| 87927ce9f2 | |||
| 7a8cbc40f8 | |||
| 1aeabff1d9 | |||
| 6adb649816 | |||
| afdbbecf70 | |||
| 412987120e | |||
| 628f2dd510 | |||
| 4c2399d246 | |||
| 9c57fcb327 | |||
| 2ab998db03 | |||
| 3e27d2970b | |||
| 34ec884578 | |||
| beb88e2453 | |||
| 0b23644b8d | |||
| e6c0f72cef | |||
| 9b47c236a5 | |||
| 091319a599 | |||
| 33eac436b9 | |||
| f27b5700e8 | |||
| 67b9e7df11 | |||
| 4a51850e9b | |||
| bf55209bf6 | |||
| 3cee4d0112 | |||
| 50dabcd838 | |||
| c7c8e3372b | |||
| a085a454e0 | |||
| 5140846fb6 | |||
| c5b0f4a05f | |||
| 98104222cf | |||
| cb1dc3f4b5 | |||
| 7e584cdab4 | |||
| 6312c65622 | |||
| 924b7d809c | |||
| 458be0380e | |||
| 7deaf47e65 | |||
| 214f0acf29 | |||
| 1ea443cdcf | |||
| 6186928374 | |||
| b4db69859d | |||
| 7b3f0254fd | |||
| 8627c3fc32 | |||
| ab5d40828e | |||
| dbb7c07695 | |||
| 6840f31fa3 | |||
| debf7d0207 | |||
| 0538db7103 | |||
| 1e981242ad | |||
| 135a631bcc | |||
| f2624d5193 | |||
| ada3a84bec | |||
| 7e7aaa293e | |||
| 5d623cce9f | |||
| 055838aaaf | |||
| a8327c3c67 | |||
| 36c91f67e4 | |||
| 4cc53d822f | |||
| 9875de0383 | |||
| 6ed858a4ca | |||
| 38192ae835 | |||
| b5e8853e6b | |||
| a98224e652 | |||
| 73a58266be | |||
| edd523534c |
+11
-38
@@ -17,13 +17,13 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ ubuntu-latest, windows-latest, macos-latest ]
|
||||
java: [ 11, 17, 21 ]
|
||||
java: [ 8, 11, 17, 20 ]
|
||||
runs-on: ${{ matrix.os }}
|
||||
permissions:
|
||||
checks: write
|
||||
steps:
|
||||
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
|
||||
- uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
- uses: actions/setup-java@5ffc13f4174014e2d4d4572b3d74c3fa61aeb2c2 # v3.11.0
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: ${{ matrix.java }}
|
||||
@@ -32,40 +32,13 @@ jobs:
|
||||
- name: Run Tests
|
||||
run: mvn --batch-mode --no-transfer-progress test
|
||||
- name: Publish Test Report
|
||||
uses: mikepenz/action-junit-report@db71d41eb79864e25ab0337e395c352e84523afe # v4.3.1
|
||||
uses: mikepenz/action-junit-report@150e2f992e4fad1379da2056d1d1c279f520e058 # v3.8.0
|
||||
if: ${{ !cancelled() }}
|
||||
with:
|
||||
report_paths: "**/target/surefire-reports/TEST*.xml"
|
||||
check_name: Unit Test Results for OpenJDK ${{ matrix.java }} on ${{ matrix.os }}
|
||||
|
||||
test-jdk8:
|
||||
name: Test OpenJDK ${{ matrix.java }} on ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ ubuntu-latest, windows-latest, macos-13 ]
|
||||
java: [ 8 ]
|
||||
runs-on: ${{ matrix.os }}
|
||||
permissions:
|
||||
checks: write
|
||||
steps:
|
||||
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
|
||||
- uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: ${{ matrix.java }}
|
||||
java-package: jdk
|
||||
cache: 'maven'
|
||||
- name: Run Tests
|
||||
run: mvn --batch-mode --no-transfer-progress test
|
||||
- name: Publish Test Report
|
||||
uses: mikepenz/action-junit-report@db71d41eb79864e25ab0337e395c352e84523afe # v4.3.1
|
||||
if: ${{ !cancelled() }}
|
||||
with:
|
||||
report_paths: "**/target/surefire-reports/TEST*.xml"
|
||||
check_name: Unit Test Results for OpenJDK ${{ matrix.java }} on ${{ matrix.os }}
|
||||
|
||||
test-oracle:
|
||||
test_oracle:
|
||||
name: Test Oracle JDK 8 with KCMS=${{ matrix.kcms }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
@@ -74,11 +47,11 @@ jobs:
|
||||
matrix:
|
||||
kcms: [ true, false ]
|
||||
steps:
|
||||
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
- run: |
|
||||
download_url="https://javadl.oracle.com/webapps/download/AutoDL?BundleId=245038_d3c52aa6bfa54d3ca74e617f18309292"
|
||||
wget -O $RUNNER_TEMP/java_package.tar.gz $download_url
|
||||
- uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0
|
||||
- uses: actions/setup-java@5ffc13f4174014e2d4d4572b3d74c3fa61aeb2c2 # v3.11.0
|
||||
with:
|
||||
distribution: 'jdkfile'
|
||||
jdkFile: ${{ runner.temp }}/java_package.tar.gz
|
||||
@@ -93,7 +66,7 @@ jobs:
|
||||
- name: Run Tests
|
||||
run: mvn --batch-mode --no-transfer-progress test
|
||||
- name: Publish Test Report
|
||||
uses: mikepenz/action-junit-report@db71d41eb79864e25ab0337e395c352e84523afe # v4.3.1
|
||||
uses: mikepenz/action-junit-report@150e2f992e4fad1379da2056d1d1c279f520e058 # v3.8.0
|
||||
if: ${{ !cancelled() }}
|
||||
with:
|
||||
report_paths: "**/target/surefire-reports/TEST*.xml"
|
||||
@@ -101,13 +74,13 @@ jobs:
|
||||
|
||||
release:
|
||||
name: Deploy
|
||||
needs: [ test, test-jdk8, test-oracle ]
|
||||
needs: [ test, test_oracle ]
|
||||
if: github.ref == 'refs/heads/master' # only perform on latest master
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
- name: Set up Maven Central
|
||||
uses: actions/setup-java@b36c23c0d998641eff861008f374ee103c25ac73 # v4.4.0
|
||||
uses: actions/setup-java@5ffc13f4174014e2d4d4572b3d74c3fa61aeb2c2 # v3.11.0
|
||||
with: # running setup-java again overwrites the settings.xml
|
||||
distribution: 'temurin'
|
||||
java-version: '8'
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ "master" ]
|
||||
schedule:
|
||||
- cron: '26 13 * * 6'
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
# Runner size impacts CodeQL analysis time. To learn more, please see:
|
||||
# - https://gh.io/recommended-hardware-resources-for-running-codeql
|
||||
# - https://gh.io/supported-runners-and-hardware-resources
|
||||
# - https://gh.io/using-larger-runners
|
||||
# Consider using larger runners for possible analysis time improvements.
|
||||
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
|
||||
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'java' ]
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea # v3.26.11
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
|
||||
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
||||
# queries: security-extended,security-and-quality
|
||||
|
||||
|
||||
# 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)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea # v3.26.11
|
||||
|
||||
# ℹ️ 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
|
||||
|
||||
# If the Autobuild fails above, remove it and uncomment the following three lines.
|
||||
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
|
||||
|
||||
# - run: |
|
||||
# echo "Run, Build Application using script"
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea # v3.26.11
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
@@ -1,62 +0,0 @@
|
||||
# This workflow uses actions that are not certified by GitHub. They are provided
|
||||
# by a third-party and are governed by separate terms of service, privacy
|
||||
# policy, and support documentation.
|
||||
|
||||
name: Scorecard supply-chain security
|
||||
on:
|
||||
# For Branch-Protection check. Only the default branch is supported. See
|
||||
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
|
||||
branch_protection_rule:
|
||||
# To guarantee Maintained check is occasionally updated. See
|
||||
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
|
||||
schedule:
|
||||
- cron: '38 8 * * 2'
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
|
||||
permissions: read-all # Declare default permissions as read only.
|
||||
|
||||
jobs:
|
||||
analysis:
|
||||
name: Scorecard analysis
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
security-events: write # to upload the results to code-scanning dashboard.
|
||||
id-token: write # to publish results and get a badge
|
||||
|
||||
steps:
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
|
||||
# you want to enable the Branch-Protection check on the repository
|
||||
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-fine-grained-pat-optional.
|
||||
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
|
||||
|
||||
# Publish Results:
|
||||
# - Publish results to OpenSSF REST API for easy access by consumers
|
||||
# - Allows the repository to include the Scorecard badge.
|
||||
# - See https://github.com/ossf/scorecard-action#publishing-results.
|
||||
publish_results: true
|
||||
|
||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||
# format to the repository Actions tab.
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # v4.4.0
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
retention-days: 5
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@6db8d6351fd0be61f9ed8ebd12ccd35dcec51fea # v3.26.11
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
@@ -15,4 +15,3 @@ private
|
||||
profiles.xml
|
||||
Thumbs.db
|
||||
.DS_Store
|
||||
/.metadata/
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
[](https://github.com/haraldk/TwelveMonkeys/actions/workflows/ci.yml)
|
||||
[](https://github.com/haraldk/TwelveMonkeys/actions/workflows/codeql.yml)
|
||||
[](https://securityscorecards.dev/viewer/?uri=github.com/haraldk/TwelveMonkeys)
|
||||
[](https://www.bestpractices.dev/projects/7900)
|
||||
|
||||
[](https://search.maven.org/search?q=g:com.twelvemonkeys.imageio)
|
||||
[](https://oss.sonatype.org/content/repositories/snapshots/com/twelvemonkeys/)
|
||||
[](https://stackoverflow.com/questions/tagged/twelvemonkeys)
|
||||
@@ -278,12 +274,12 @@ To depend on the JPEG and TIFF plugin using Maven, add the following to your POM
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio-jpeg</artifactId>
|
||||
<version>3.10.1</version>
|
||||
<version>3.9.4</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio-tiff</artifactId>
|
||||
<version>3.10.1</version>
|
||||
<version>3.9.4</version>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
@@ -293,7 +289,7 @@ To depend on the JPEG and TIFF plugin using Maven, add the following to your POM
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.servlet</groupId>
|
||||
<artifactId>servlet</artifactId>
|
||||
<version>3.10.1</version>
|
||||
<version>3.9.4</version>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
@@ -302,7 +298,7 @@ To depend on the JPEG and TIFF plugin using Maven, add the following to your POM
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.servlet</groupId>
|
||||
<artifactId>servlet</artifactId>
|
||||
<version>3.10.1</version>
|
||||
<version>3.9.4</version>
|
||||
<classifier>jakarta</classifier>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
@@ -312,18 +308,18 @@ To depend on the JPEG and TIFF plugin using Maven, add the following to your POM
|
||||
|
||||
To depend on the JPEG and TIFF plugin in your IDE or program, add all of the following JARs to your class path:
|
||||
|
||||
twelvemonkeys-common-lang-3.10.1.jar
|
||||
twelvemonkeys-common-io-3.10.1.jar
|
||||
twelvemonkeys-common-image-3.10.1.jar
|
||||
twelvemonkeys-imageio-core-3.10.1.jar
|
||||
twelvemonkeys-imageio-metadata-3.10.1.jar
|
||||
twelvemonkeys-imageio-jpeg-3.10.1.jar
|
||||
twelvemonkeys-imageio-tiff-3.10.1.jar
|
||||
twelvemonkeys-common-lang-3.9.4.jar
|
||||
twelvemonkeys-common-io-3.9.4.jar
|
||||
twelvemonkeys-common-image-3.9.4.jar
|
||||
twelvemonkeys-imageio-core-3.9.4.jar
|
||||
twelvemonkeys-imageio-metadata-3.9.4.jar
|
||||
twelvemonkeys-imageio-jpeg-3.9.4.jar
|
||||
twelvemonkeys-imageio-tiff-3.9.4.jar
|
||||
|
||||
#### Deploying the plugins in a web app
|
||||
|
||||
Because the `ImageIO` plugin registry (the `IIORegistry`) is "VM global", it does not work well with
|
||||
servlet contexts as-is. This is especially evident if you load plugins from the `WEB-INF/lib` or `classes` folder.
|
||||
Because the `ImageIO` plugin registry (the `IIORegistry`) is "VM global", it doesn't by default work well with
|
||||
servlet contexts. This is especially evident if you load plugins from the `WEB-INF/lib` or `classes` folder.
|
||||
Unless you add `ImageIO.scanForPlugins()` somewhere in your code, the plugins might never be available at all.
|
||||
|
||||
In addition, servlet contexts dynamically loads and unloads classes (using a new class loader per context).
|
||||
@@ -359,16 +355,6 @@ or other ImageIO plugins as well.
|
||||
|
||||
Another safe option, is to place the JAR files in the application server's shared or common lib folder.
|
||||
|
||||
##### Jakarta Servlet Support
|
||||
|
||||
For those transitioning from the old `javax.servlet` to the new `jakarta.servlet` package, there is a separate
|
||||
dependency available. It contains exactly the same servlet classes as mentioned above, but built against the new Jakarta EE
|
||||
packages. The dependency has the same group name and identifier as before, but a `jakarta` *classifier* appended, to
|
||||
distinguish it from the non-Jakarta package.
|
||||
|
||||
See the [Maven dependency example](#maven-dependency-example) for how to enable it with Maven.
|
||||
Gradle or other build tools will have similar options.
|
||||
|
||||
#### Including the plugins in a "fat" JAR
|
||||
|
||||
The recommended way to use the plugins, is just to include the JARs as-is in your project, through a Maven dependency or similar.
|
||||
@@ -394,44 +380,44 @@ Other "fat" JAR bundlers will probably have similar mechanisms to merge entries
|
||||
|
||||
### Links to prebuilt binaries
|
||||
|
||||
##### Latest version (3.10.1)
|
||||
##### Latest version (3.9.4)
|
||||
|
||||
The latest version that will run on Java 7 is 3.9.4. Later versions will require Java 8 or later.
|
||||
|
||||
Common dependencies
|
||||
* [common-lang-3.10.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-lang/3.10.1/common-lang-3.10.1.jar)
|
||||
* [common-io-3.10.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-io/3.10.1/common-io-3.10.1.jar)
|
||||
* [common-image-3.10.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-image/3.10.1/common-image-3.10.1.jar)
|
||||
* [common-lang-3.9.4.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-lang/3.9.4/common-lang-3.9.4.jar)
|
||||
* [common-io-3.9.4.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-io/3.9.4/common-io-3.9.4.jar)
|
||||
* [common-image-3.9.4.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-image/3.9.4/common-image-3.9.4.jar)
|
||||
|
||||
ImageIO dependencies
|
||||
* [imageio-core-3.10.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-core/3.10.1/imageio-core-3.10.1.jar)
|
||||
* [imageio-metadata-3.10.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-metadata/3.10.1/imageio-metadata-3.10.1.jar)
|
||||
* [imageio-core-3.9.4.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-core/3.9.4/imageio-core-3.9.4.jar)
|
||||
* [imageio-metadata-3.9.4.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-metadata/3.9.4/imageio-metadata-3.9.4.jar)
|
||||
|
||||
ImageIO plugins
|
||||
* [imageio-bmp-3.10.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-bmp/3.10.1/imageio-bmp-3.10.1.jar)
|
||||
* [imageio-hdr-3.10.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-hdr/3.10.1/imageio-hdr-3.10.1.jar)
|
||||
* [imageio-icns-3.10.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-icns/3.10.1/imageio-icns-3.10.1.jar)
|
||||
* [imageio-iff-3.10.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-iff/3.10.1/imageio-iff-3.10.1.jar)
|
||||
* [imageio-jpeg-3.10.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jpeg/3.10.1/imageio-jpeg-3.10.1.jar)
|
||||
* [imageio-pcx-3.10.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pcx/3.10.1/imageio-pcx-3.10.1.jar)
|
||||
* [imageio-pict-3.10.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pict/3.10.1/imageio-pict-3.10.1.jar)
|
||||
* [imageio-pnm-3.10.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pnm/3.10.1/imageio-pnm-3.10.1.jar)
|
||||
* [imageio-psd-3.10.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-psd/3.10.1/imageio-psd-3.10.1.jar)
|
||||
* [imageio-sgi-3.10.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-sgi/3.10.1/imageio-sgi-3.10.1.jar)
|
||||
* [imageio-tga-3.10.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tga/3.10.1/imageio-tga-3.10.1.jar)
|
||||
* [imageio-thumbsdb-3.10.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-thumbsdb/3.10.1/imageio-thumbsdb-3.10.1.jar)
|
||||
* [imageio-tiff-3.10.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tiff/3.10.1/imageio-tiff-3.10.1.jar)
|
||||
* [imageio-webp-3.10.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-webp/3.10.1/imageio-webp-3.10.1.jar)
|
||||
* [imageio-xwd-3.10.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-xwd/3.10.1/imageio-xwd-3.10.1.jar)
|
||||
* [imageio-bmp-3.9.4.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-bmp/3.9.4/imageio-bmp-3.9.4.jar)
|
||||
* [imageio-hdr-3.9.4.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-hdr/3.9.4/imageio-hdr-3.9.4.jar)
|
||||
* [imageio-icns-3.9.4.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-icns/3.9.4/imageio-icns-3.9.4.jar)
|
||||
* [imageio-iff-3.9.4.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-iff/3.9.4/imageio-iff-3.9.4.jar)
|
||||
* [imageio-jpeg-3.9.4.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jpeg/3.9.4/imageio-jpeg-3.9.4.jar)
|
||||
* [imageio-pcx-3.9.4.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pcx/3.9.4/imageio-pcx-3.9.4.jar)
|
||||
* [imageio-pict-3.9.4.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pict/3.9.4/imageio-pict-3.9.4.jar)
|
||||
* [imageio-pnm-3.9.4.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pnm/3.9.4/imageio-pnm-3.9.4.jar)
|
||||
* [imageio-psd-3.9.4.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-psd/3.9.4/imageio-psd-3.9.4.jar)
|
||||
* [imageio-sgi-3.9.4.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-sgi/3.9.4/imageio-sgi-3.9.4.jar)
|
||||
* [imageio-tga-3.9.4.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tga/3.9.4/imageio-tga-3.9.4.jar)
|
||||
* [imageio-thumbsdb-3.9.4.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-thumbsdb/3.9.4/imageio-thumbsdb-3.9.4.jar)
|
||||
* [imageio-tiff-3.9.4.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tiff/3.9.4/imageio-tiff-3.9.4.jar)
|
||||
* [imageio-webp-3.9.4.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-webp/3.9.4/imageio-webp-3.9.4.jar)
|
||||
* [imageio-xwd-3.9.4.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-xwd/3.9.4/imageio-xwd-3.9.4.jar)
|
||||
|
||||
ImageIO plugins requiring 3rd party libs
|
||||
* [imageio-batik-3.10.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-batik/3.10.1/imageio-batik-3.10.1.jar)
|
||||
* [imageio-batik-3.9.4.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-batik/3.9.4/imageio-batik-3.9.4.jar)
|
||||
|
||||
Photoshop Path support for ImageIO
|
||||
* [imageio-clippath-3.10.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-clippath/3.10.1/imageio-clippath-3.10.1.jar)
|
||||
* [imageio-clippath-3.9.4.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-clippath/3.9.4/imageio-clippath-3.9.4.jar)
|
||||
|
||||
Servlet support
|
||||
* [servlet-3.10.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/servlet/servlet/3.10.1/servlet-3.10.1.jar)
|
||||
* [servlet-3.9.4.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/servlet/servlet/3.9.4/servlet-3.9.4.jar)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
+1
-6
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys</groupId>
|
||||
<artifactId>twelvemonkeys</artifactId>
|
||||
<version>3.12.0</version>
|
||||
<version>3.9.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<groupId>com.twelvemonkeys.bom</groupId>
|
||||
@@ -63,11 +63,6 @@
|
||||
<artifactId>imageio-hdr</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio-dds</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio-icns</artifactId>
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
<version>3.12.0</version>
|
||||
<version>3.9.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>common-image</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>TwelveMonkeys :: Common :: Image</name>
|
||||
<description>
|
||||
TwelveMonkeys Common image support classes.
|
||||
The TwelveMonkeys Common Image support
|
||||
</description>
|
||||
|
||||
<properties>
|
||||
@@ -28,14 +28,12 @@
|
||||
<artifactId>common-io</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jmagick</groupId>
|
||||
<artifactId>jmagick</artifactId>
|
||||
<version>6.6.9</version>
|
||||
<optional>true</optional>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
@@ -844,7 +844,7 @@ public final class ImageUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < mapSize1; i++) {
|
||||
for (int i = 0; i > mapSize1; i++) {
|
||||
if (icm1.getRGB(i) != icm2.getRGB(i)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Regular → Executable
+18
-12
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Harald Kuhr
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -28,22 +28,28 @@
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.dds;
|
||||
|
||||
import com.twelvemonkeys.imageio.spi.ReaderWriterProviderInfo;
|
||||
import com.twelvemonkeys.imageio.spi.ReaderWriterProviderInfoTest;
|
||||
package com.twelvemonkeys.image;
|
||||
|
||||
/**
|
||||
* DDSProviderInfoTest.
|
||||
* Magick
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: harald.kuhr$
|
||||
* @version $Id: DDSProviderInfoTest.java,v 1.0 02/06/16 harald.kuhr Exp$
|
||||
* @author last modified by $Author: haku $
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/image/Magick.java#1 $
|
||||
*/
|
||||
public class DDSProviderInfoTest extends ReaderWriterProviderInfoTest {
|
||||
final class Magick {
|
||||
static final boolean DEBUG = useDebug();
|
||||
|
||||
@Override
|
||||
protected ReaderWriterProviderInfo createProviderInfo() {
|
||||
return new DDSProviderInfo();
|
||||
private static boolean useDebug() {
|
||||
try {
|
||||
return "TRUE".equalsIgnoreCase(System.getProperty("com.twelvemonkeys.image.magick.debug"));
|
||||
}
|
||||
catch (Throwable t) {
|
||||
// Most probably in case of a SecurityManager
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Magick() {}
|
||||
}
|
||||
+187
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
package com.twelvemonkeys.image;
|
||||
|
||||
import com.twelvemonkeys.lang.SystemUtil;
|
||||
import magick.MagickImage;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.BufferedImageOp;
|
||||
|
||||
/**
|
||||
* This class accelerates certain graphics operations, using
|
||||
* JMagick and ImageMagick, if available.
|
||||
* If those libraries are not installed, this class silently does nothing.
|
||||
* <p>
|
||||
* Set the system property {@code "com.twelvemonkeys.image.accel"} to
|
||||
* {@code false}, to disable, even if JMagick is installed.
|
||||
* Set the system property {@code "com.twelvemonkeys.image.magick.debug"} to
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/image/MagickAccelerator.java#3 $
|
||||
*/
|
||||
final class MagickAccelerator {
|
||||
|
||||
private static final boolean DEBUG = Magick.DEBUG;
|
||||
private static final boolean USE_MAGICK = useMagick();
|
||||
|
||||
private static final int RESAMPLE_OP = 0;
|
||||
|
||||
private static Class[] nativeOp = new Class[1];
|
||||
|
||||
static {
|
||||
try {
|
||||
nativeOp[RESAMPLE_OP] = Class.forName("com.twelvemonkeys.image.ResampleOp");
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
System.err.println("Could not find class: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean useMagick() {
|
||||
try {
|
||||
boolean available = SystemUtil.isClassAvailable("magick.MagickImage");
|
||||
|
||||
if (DEBUG && !available) {
|
||||
System.err.print("ImageMagick bindings not available.");
|
||||
}
|
||||
|
||||
boolean useMagick =
|
||||
available && !"FALSE".equalsIgnoreCase(System.getProperty("com.twelvemonkeys.image.accel"));
|
||||
|
||||
if (DEBUG) {
|
||||
System.err.println(
|
||||
useMagick
|
||||
? "Will use ImageMagick bindings to accelerate image resampling operations."
|
||||
: "Will not use ImageMagick to accelerate image resampling operations."
|
||||
);
|
||||
}
|
||||
|
||||
return useMagick;
|
||||
}
|
||||
catch (Throwable t) {
|
||||
// Most probably in case of a SecurityManager
|
||||
System.err.println("Could not enable ImageMagick bindings: " + t);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static int getNativeOpIndex(Class pOpClass) {
|
||||
for (int i = 0; i < nativeOp.length; i++) {
|
||||
if (pOpClass == nativeOp[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static BufferedImage filter(BufferedImageOp pOperation, BufferedImage pInput, BufferedImage pOutput) {
|
||||
if (!USE_MAGICK) {
|
||||
return null;
|
||||
}
|
||||
|
||||
BufferedImage result = null;
|
||||
switch (getNativeOpIndex(pOperation.getClass())) {
|
||||
case RESAMPLE_OP:
|
||||
ResampleOp resample = (ResampleOp) pOperation;
|
||||
result = resampleMagick(pInput, resample.width, resample.height, resample.filterType);
|
||||
|
||||
// NOTE: If output parameter is non-null, we have to return that
|
||||
// image, instead of result
|
||||
if (pOutput != null) {
|
||||
//pOutput.setData(result.getRaster()); // Fast, but less compatible
|
||||
// NOTE: For some reason, this is sometimes super-slow...?
|
||||
ImageUtil.drawOnto(pOutput, result);
|
||||
result = pOutput;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
// Simply fall through, allowing acceleration to be added later
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static BufferedImage resampleMagick(BufferedImage pSrc, int pWidth, int pHeight, int pFilterType) {
|
||||
// Convert to Magick, scale and convert back
|
||||
MagickImage image = null;
|
||||
MagickImage scaled = null;
|
||||
try {
|
||||
image = MagickUtil.toMagick(pSrc);
|
||||
|
||||
long start = 0;
|
||||
if (DEBUG) {
|
||||
start = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
// NOTE: setFilter affects zoomImage, NOT scaleImage
|
||||
image.setFilter(pFilterType);
|
||||
scaled = image.zoomImage(pWidth, pHeight);
|
||||
//scaled = image.scaleImage(pWidth, pHeight); // AREA_AVERAGING
|
||||
|
||||
if (DEBUG) {
|
||||
long time = System.currentTimeMillis() - start;
|
||||
System.out.println("Filtered: " + time + " ms");
|
||||
}
|
||||
|
||||
return MagickUtil.toBuffered(scaled);
|
||||
}
|
||||
//catch (MagickException e) {
|
||||
catch (Exception e) {
|
||||
// NOTE: Stupid workaround: If MagickException is caught, a
|
||||
// NoClassDefFoundError is thrown, when MagickException class is
|
||||
// unavailable...
|
||||
if (e instanceof RuntimeException) {
|
||||
throw (RuntimeException) e;
|
||||
}
|
||||
|
||||
throw new ImageConversionException(e.getMessage(), e);
|
||||
}
|
||||
finally {
|
||||
// NOTE: ImageMagick might be unstable after a while, if image data
|
||||
// is not deallocated. The GC/finalize method handles this, but in
|
||||
// special circumstances, it's not triggered often enough.
|
||||
if (image != null) {
|
||||
image.destroyImages();
|
||||
}
|
||||
if (scaled != null) {
|
||||
scaled.destroyImages();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,621 @@
|
||||
/*
|
||||
* Copyright (c) 2008, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.image;
|
||||
|
||||
import magick.ImageType;
|
||||
import magick.MagickException;
|
||||
import magick.MagickImage;
|
||||
import magick.PixelPacket;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.color.ICC_ColorSpace;
|
||||
import java.awt.color.ICC_Profile;
|
||||
import java.awt.image.*;
|
||||
|
||||
/**
|
||||
* Utility for converting JMagick {@code MagickImage}s to standard Java
|
||||
* {@code BufferedImage}s and back.
|
||||
* <p>
|
||||
* <em>NOTE: This class is considered an implementation detail and not part of
|
||||
* the public API. This class is subject to change without further notice.
|
||||
* You have been warned. :-)</em>
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/image/MagickUtil.java#4 $
|
||||
*/
|
||||
public final class MagickUtil {
|
||||
// IMPORTANT NOTE: Disaster happens if any of these constants are used outside this class
|
||||
// because you then have a dependency on MagickException (this is due to Java class loading
|
||||
// and initialization magic).
|
||||
// Do not use outside this class. If the constants need to be shared, move to Magick or ImageUtil.
|
||||
|
||||
/** Color Model usesd for bilevel (B/W) */
|
||||
private static final IndexColorModel CM_MONOCHROME = MonochromeColorModel.getInstance();
|
||||
|
||||
/** Color Model usesd for raw ABGR */
|
||||
private static final ColorModel CM_COLOR_ALPHA =
|
||||
new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), new int[] {8, 8, 8, 8},
|
||||
true, true, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
|
||||
|
||||
/** Color Model usesd for raw BGR */
|
||||
private static final ColorModel CM_COLOR_OPAQUE =
|
||||
new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), new int[] {8, 8, 8},
|
||||
false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
|
||||
|
||||
/** Color Model usesd for raw RGB */
|
||||
//private static final ColorModel CM_COLOR_RGB = new DirectColorModel(24, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x0);
|
||||
|
||||
/** Color Model usesd for raw GRAY + ALPHA */
|
||||
private static final ColorModel CM_GRAY_ALPHA =
|
||||
new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
|
||||
true, true, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
|
||||
|
||||
/** Color Model usesd for raw GRAY */
|
||||
private static final ColorModel CM_GRAY_OPAQUE =
|
||||
new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
|
||||
false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
|
||||
|
||||
/** Band offsets for raw ABGR */
|
||||
private static final int[] BAND_OFF_TRANS = new int[] {3, 2, 1, 0};
|
||||
|
||||
/** Band offsets for raw BGR */
|
||||
private static final int[] BAND_OFF_OPAQUE = new int[] {2, 1, 0};
|
||||
|
||||
/** The point at {@code 0, 0} */
|
||||
private static final Point LOCATION_UPPER_LEFT = new Point(0, 0);
|
||||
|
||||
private static final boolean DEBUG = Magick.DEBUG;
|
||||
|
||||
// Only static members and methods
|
||||
private MagickUtil() {}
|
||||
|
||||
/**
|
||||
* Converts a {@code MagickImage} to a {@code BufferedImage}.
|
||||
* <p>
|
||||
* The conversion depends on {@code pImage}'s {@code ImageType}:
|
||||
* </p>
|
||||
* <dl>
|
||||
* <dt>{@code ImageType.BilevelType}</dt>
|
||||
* <dd>{@code BufferedImage} of type {@code TYPE_BYTE_BINARY}</dd>
|
||||
*
|
||||
* <dt>{@code ImageType.GrayscaleType}</dt>
|
||||
* <dd>{@code BufferedImage} of type {@code TYPE_BYTE_GRAY}</dd>
|
||||
* <dt>{@code ImageType.GrayscaleMatteType}</dt>
|
||||
* <dd>{@code BufferedImage} of type {@code TYPE_USHORT_GRAY}</dd>
|
||||
*
|
||||
* <dt>{@code ImageType.PaletteType}</dt>
|
||||
* <dd>{@code BufferedImage} of type {@code TYPE_BYTE_BINARY} (for images
|
||||
* with a palette of <= 16 colors) or {@code TYPE_BYTE_INDEXED}</dd>
|
||||
* <dt>{@code ImageType.PaletteMatteType}</dt>
|
||||
* <dd>{@code BufferedImage} of type {@code TYPE_BYTE_BINARY} (for images
|
||||
* with a palette of <= 16 colors) or {@code TYPE_BYTE_INDEXED}</dd>
|
||||
*
|
||||
* <dt>{@code ImageType.TrueColorType}</dt>
|
||||
* <dd>{@code BufferedImage} of type {@code TYPE_3BYTE_BGR}</dd>
|
||||
* <dt>{@code ImageType.TrueColorPaletteType}</dt>
|
||||
* <dd>{@code BufferedImage} of type {@code TYPE_4BYTE_ABGR}</dd>
|
||||
* </dl>
|
||||
*
|
||||
* @param pImage the original {@code MagickImage}
|
||||
* @return a new {@code BufferedImage}
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code pImage} is {@code null}
|
||||
* or if the {@code ImageType} is not one mentioned above.
|
||||
* @throws MagickException if an exception occurs during conversion
|
||||
*
|
||||
* @see BufferedImage
|
||||
*/
|
||||
public static BufferedImage toBuffered(MagickImage pImage) throws MagickException {
|
||||
if (pImage == null) {
|
||||
throw new IllegalArgumentException("image == null");
|
||||
}
|
||||
|
||||
long start = 0L;
|
||||
if (DEBUG) {
|
||||
start = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
BufferedImage image = null;
|
||||
try {
|
||||
switch (pImage.getImageType()) {
|
||||
case ImageType.BilevelType:
|
||||
image = bilevelToBuffered(pImage);
|
||||
break;
|
||||
case ImageType.GrayscaleType:
|
||||
image = grayToBuffered(pImage, false);
|
||||
break;
|
||||
case ImageType.GrayscaleMatteType:
|
||||
image = grayToBuffered(pImage, true);
|
||||
break;
|
||||
case ImageType.PaletteType:
|
||||
image = paletteToBuffered(pImage, false);
|
||||
break;
|
||||
case ImageType.PaletteMatteType:
|
||||
image = paletteToBuffered(pImage, true);
|
||||
break;
|
||||
case ImageType.TrueColorType:
|
||||
image = rgbToBuffered(pImage, false);
|
||||
break;
|
||||
case ImageType.TrueColorMatteType:
|
||||
image = rgbToBuffered(pImage, true);
|
||||
break;
|
||||
case ImageType.ColorSeparationType:
|
||||
image = cmykToBuffered(pImage, false);
|
||||
break;
|
||||
case ImageType.ColorSeparationMatteType:
|
||||
image = cmykToBuffered(pImage, true);
|
||||
break;
|
||||
case ImageType.OptimizeType:
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown JMagick image type: " + pImage.getImageType());
|
||||
}
|
||||
|
||||
}
|
||||
finally {
|
||||
if (DEBUG) {
|
||||
long time = System.currentTimeMillis() - start;
|
||||
System.out.println("Converted JMagick image type: " + pImage.getImageType() + " to BufferedImage: " + image);
|
||||
System.out.println("Conversion to BufferedImage: " + time + " ms");
|
||||
}
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a {@code BufferedImage} to a {@code MagickImage}.
|
||||
* <p>
|
||||
* The conversion depends on {@code pImage}'s {@code ColorModel}:
|
||||
* </p>
|
||||
* <dl>
|
||||
* <dt>{@code IndexColorModel} with 1 bit b/w</dt>
|
||||
* <dd>{@code MagickImage} of type {@code ImageType.BilevelType}</dd>
|
||||
* <dt>{@code IndexColorModel} > 1 bit,</dt>
|
||||
* <dd>{@code MagickImage} of type {@code ImageType.PaletteType}
|
||||
* or {@code MagickImage} of type {@code ImageType.PaletteMatteType}
|
||||
* depending on <tt>ColorModel.getAlpha()</tt></dd>
|
||||
*
|
||||
* <dt>{@code ColorModel.getColorSpace().getType() == ColorSpace.TYPE_GRAY}</dt>
|
||||
* <dd>{@code MagickImage} of type {@code ImageType.GrayscaleType}
|
||||
* or {@code MagickImage} of type {@code ImageType.GrayscaleMatteType}
|
||||
* depending on <tt>ColorModel.getAlpha()</tt></dd>
|
||||
*
|
||||
* <dt>{@code ColorModel.getColorSpace().getType() == ColorSpace.TYPE_RGB}</dt>
|
||||
* <dd>{@code MagickImage} of type {@code ImageType.TrueColorType}
|
||||
* or {@code MagickImage} of type {@code ImageType.TrueColorPaletteType}</dd>
|
||||
* </dl>
|
||||
*
|
||||
* @param pImage the original {@code BufferedImage}
|
||||
* @return a new {@code MagickImage}
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code pImage} is {@code null}
|
||||
* or if the {@code ColorModel} is not one mentioned above.
|
||||
* @throws MagickException if an exception occurs during conversion
|
||||
*
|
||||
* @see BufferedImage
|
||||
*/
|
||||
public static MagickImage toMagick(BufferedImage pImage) throws MagickException {
|
||||
if (pImage == null) {
|
||||
throw new IllegalArgumentException("image == null");
|
||||
}
|
||||
|
||||
long start = 0L;
|
||||
if (DEBUG) {
|
||||
start = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
try {
|
||||
ColorModel cm = pImage.getColorModel();
|
||||
if (cm instanceof IndexColorModel) {
|
||||
// Handles both BilevelType, PaletteType and PaletteMatteType
|
||||
return indexedToMagick(pImage, (IndexColorModel) cm, cm.hasAlpha());
|
||||
}
|
||||
|
||||
switch (cm.getColorSpace().getType()) {
|
||||
case ColorSpace.TYPE_GRAY:
|
||||
// Handles GrayType and GrayMatteType
|
||||
return grayToMagick(pImage, cm.hasAlpha());
|
||||
case ColorSpace.TYPE_RGB:
|
||||
// Handles TrueColorType and TrueColorMatteType
|
||||
return rgbToMagic(pImage, cm.hasAlpha());
|
||||
case ColorSpace.TYPE_CMY:
|
||||
case ColorSpace.TYPE_CMYK:
|
||||
case ColorSpace.TYPE_HLS:
|
||||
case ColorSpace.TYPE_HSV:
|
||||
// Other types not supported yet
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown buffered image type: " + pImage);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (DEBUG) {
|
||||
long time = System.currentTimeMillis() - start;
|
||||
System.out.println("Conversion to MagickImage: " + time + " ms");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static MagickImage rgbToMagic(BufferedImage pImage, boolean pAlpha) throws MagickException {
|
||||
MagickImage image = new MagickImage();
|
||||
|
||||
BufferedImage buffered = ImageUtil.toBuffered(pImage, pAlpha ? BufferedImage.TYPE_4BYTE_ABGR : BufferedImage.TYPE_3BYTE_BGR);
|
||||
|
||||
// Need to get data of sub raster, not the full data array, this is
|
||||
// just a convenient way
|
||||
Raster raster;
|
||||
if (buffered.getRaster().getParent() != null) {
|
||||
raster = buffered.getData(new Rectangle(buffered.getWidth(), buffered.getHeight()));
|
||||
}
|
||||
else {
|
||||
raster = buffered.getRaster();
|
||||
}
|
||||
|
||||
image.constituteImage(buffered.getWidth(), buffered.getHeight(), pAlpha ? "ABGR" : "BGR",
|
||||
((DataBufferByte) raster.getDataBuffer()).getData());
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
private static MagickImage grayToMagick(BufferedImage pImage, boolean pAlpha) throws MagickException {
|
||||
MagickImage image = new MagickImage();
|
||||
|
||||
// TODO: Make a fix for TYPE_USHORT_GRAY
|
||||
// The code below does not seem to work (JMagick issues?)...
|
||||
/*
|
||||
if (pImage.getType() == BufferedImage.TYPE_USHORT_GRAY) {
|
||||
short[] data = ((DataBufferUShort) pImage.getRaster().getDataBuffer()).getData();
|
||||
int[] intData = new int[data.length];
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
intData[i] = (data[i] & 0xffff) * 0xffff;
|
||||
}
|
||||
image.constituteImage(pImage.getWidth(), pImage.getHeight(), "I", intData);
|
||||
|
||||
System.out.println("storageClass: " + image.getStorageClass());
|
||||
System.out.println("depth: " + image.getDepth());
|
||||
System.out.println("imageType: " + image.getImageType());
|
||||
}
|
||||
else {
|
||||
*/
|
||||
BufferedImage buffered = ImageUtil.toBuffered(pImage, pAlpha ? BufferedImage.TYPE_4BYTE_ABGR : BufferedImage.TYPE_BYTE_GRAY);
|
||||
|
||||
// Need to get data of sub raster, not the full data array, this is
|
||||
// just a convenient way
|
||||
Raster raster;
|
||||
if (buffered.getRaster().getParent() != null) {
|
||||
raster = buffered.getData(new Rectangle(buffered.getWidth(), buffered.getHeight()));
|
||||
}
|
||||
else {
|
||||
raster = buffered.getRaster();
|
||||
}
|
||||
|
||||
image.constituteImage(buffered.getWidth(), buffered.getHeight(), pAlpha ? "ABGR" : "I", ((DataBufferByte) raster.getDataBuffer()).getData());
|
||||
//}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
private static MagickImage indexedToMagick(BufferedImage pImage, IndexColorModel pColorModel, boolean pAlpha) throws MagickException {
|
||||
MagickImage image = rgbToMagic(pImage, pAlpha);
|
||||
|
||||
int mapSize = pColorModel.getMapSize();
|
||||
image.setNumberColors(mapSize);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
/*
|
||||
public static MagickImage toMagick(BufferedImage pImage) throws MagickException {
|
||||
if (pImage == null) {
|
||||
throw new IllegalArgumentException("image == null");
|
||||
}
|
||||
|
||||
final int width = pImage.getWidth();
|
||||
final int height = pImage.getHeight();
|
||||
|
||||
// int ARGB -> byte RGBA conversion
|
||||
// NOTE: This is ImageMagick Q16 compatible raw RGBA format with 16 bits/sample...
|
||||
// For a Q8 build, we could probably go with half the space...
|
||||
// NOTE: This is close to insanity, as it wastes extreme ammounts of memory
|
||||
final int[] argb = new int[width];
|
||||
final byte[] raw16 = new byte[width * height * 8];
|
||||
for (int y = 0; y < height; y++) {
|
||||
// Fetch one line of ARGB data
|
||||
pImage.getRGB(0, y, width, 1, argb, 0, width);
|
||||
|
||||
for (int x = 0; x < width; x++) {
|
||||
int pixel = (x + (y * width)) * 8;
|
||||
raw16[pixel ] = (byte) ((argb[x] >> 16) & 0xff); // R
|
||||
raw16[pixel + 2] = (byte) ((argb[x] >> 8) & 0xff); // G
|
||||
raw16[pixel + 4] = (byte) ((argb[x] ) & 0xff); // B
|
||||
raw16[pixel + 6] = (byte) ((argb[x] >> 24) & 0xff); // A
|
||||
}
|
||||
}
|
||||
|
||||
// Create magick image
|
||||
ImageInfo info = new ImageInfo();
|
||||
info.setMagick("RGBA"); // Raw RGBA samples
|
||||
info.setSize(width + "x" + height); // String?!?
|
||||
|
||||
MagickImage image = new MagickImage(info);
|
||||
image.setImageAttribute("depth", "8");
|
||||
|
||||
// Set pixel data in 16 bit raw RGBA format
|
||||
image.blobToImage(info, raw16);
|
||||
|
||||
return image;
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Converts a bi-level {@code MagickImage} to a {@code BufferedImage}, of
|
||||
* type {@code TYPE_BYTE_BINARY}.
|
||||
*
|
||||
* @param pImage the original {@code MagickImage}
|
||||
* @return a new {@code BufferedImage}
|
||||
*
|
||||
* @throws MagickException if an exception occurs during conversion
|
||||
*
|
||||
* @see BufferedImage
|
||||
*/
|
||||
private static BufferedImage bilevelToBuffered(MagickImage pImage) throws MagickException {
|
||||
// As there is no way to get the binary representation of the image,
|
||||
// convert to gray, and the create a binary image from it
|
||||
BufferedImage temp = grayToBuffered(pImage, false);
|
||||
|
||||
BufferedImage image = new BufferedImage(temp.getWidth(), temp.getHeight(), BufferedImage.TYPE_BYTE_BINARY, CM_MONOCHROME);
|
||||
|
||||
ImageUtil.drawOnto(image, temp);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a gray {@code MagickImage} to a {@code BufferedImage}, of
|
||||
* type {@code TYPE_USHORT_GRAY} or {@code TYPE_BYTE_GRAY}.
|
||||
*
|
||||
* @param pImage the original {@code MagickImage}
|
||||
* @param pAlpha keep alpha channel
|
||||
* @return a new {@code BufferedImage}
|
||||
*
|
||||
* @throws MagickException if an exception occurs during conversion
|
||||
*
|
||||
* @see BufferedImage
|
||||
*/
|
||||
private static BufferedImage grayToBuffered(MagickImage pImage, boolean pAlpha) throws MagickException {
|
||||
Dimension size = pImage.getDimension();
|
||||
int length = size.width * size.height;
|
||||
int bands = pAlpha ? 2 : 1;
|
||||
byte[] pixels = new byte[length * bands];
|
||||
|
||||
// TODO: Make a fix for 16 bit TYPE_USHORT_GRAY?!
|
||||
// Note: The ordering AI or I corresponds to BufferedImage
|
||||
// TYPE_CUSTOM and TYPE_BYTE_GRAY respectively
|
||||
pImage.dispatchImage(0, 0, size.width, size.height, pAlpha ? "AI" : "I", pixels);
|
||||
|
||||
// Init databuffer with array, to avoid allocation of empty array
|
||||
DataBuffer buffer = new DataBufferByte(pixels, pixels.length);
|
||||
|
||||
int[] bandOffsets = pAlpha ? new int[] {1, 0} : new int[] {0};
|
||||
|
||||
WritableRaster raster =
|
||||
Raster.createInterleavedRaster(buffer, size.width, size.height,
|
||||
size.width * bands, bands, bandOffsets, LOCATION_UPPER_LEFT);
|
||||
|
||||
return new BufferedImage(pAlpha ? CM_GRAY_ALPHA : CM_GRAY_OPAQUE, raster, pAlpha, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a palette-based {@code MagickImage} to a
|
||||
* {@code BufferedImage}, of type {@code TYPE_BYTE_BINARY} (for images
|
||||
* with a palette of <= 16 colors) or {@code TYPE_BYTE_INDEXED}.
|
||||
*
|
||||
* @param pImage the original {@code MagickImage}
|
||||
* @param pAlpha keep alpha channel
|
||||
* @return a new {@code BufferedImage}
|
||||
*
|
||||
* @throws MagickException if an exception occurs during conversion
|
||||
*
|
||||
* @see BufferedImage
|
||||
*/
|
||||
private static BufferedImage paletteToBuffered(MagickImage pImage, boolean pAlpha) throws MagickException {
|
||||
// Create indexcolormodel for the image
|
||||
IndexColorModel cm;
|
||||
|
||||
try {
|
||||
cm = createIndexColorModel(pImage.getColormap(), pAlpha);
|
||||
}
|
||||
catch (MagickException e) {
|
||||
// NOTE: Some MagickImages incorrecly (?) reports to be paletteType,
|
||||
// but does not have a colormap, this is a workaround.
|
||||
return rgbToBuffered(pImage, pAlpha);
|
||||
}
|
||||
|
||||
// As there is no way to get the indexes of an indexed image, convert to
|
||||
// RGB, and the create an indexed image from it
|
||||
BufferedImage temp = rgbToBuffered(pImage, pAlpha);
|
||||
|
||||
BufferedImage image;
|
||||
if (cm.getMapSize() <= 16) {
|
||||
image = new BufferedImage(temp.getWidth(), temp.getHeight(), BufferedImage.TYPE_BYTE_BINARY, cm);
|
||||
}
|
||||
else {
|
||||
image = new BufferedImage(temp.getWidth(), temp.getHeight(), BufferedImage.TYPE_BYTE_INDEXED, cm);
|
||||
}
|
||||
|
||||
// Create transparent background for images containing alpha
|
||||
if (pAlpha) {
|
||||
Graphics2D g = image.createGraphics();
|
||||
try {
|
||||
g.setComposite(AlphaComposite.Clear);
|
||||
g.fillRect(0, 0, temp.getWidth(), temp.getHeight());
|
||||
}
|
||||
finally {
|
||||
g.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: This is (surprisingly) much faster than using g2d.drawImage()..
|
||||
// (Tests shows 20-30ms, vs. 600-700ms on the same image)
|
||||
BufferedImageOp op = new CopyDither(cm);
|
||||
op.filter(temp, image);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@code IndexColorModel} from an array of
|
||||
* {@code PixelPacket}s.
|
||||
*
|
||||
* @param pColormap the original colormap as a {@code PixelPacket} array
|
||||
* @param pAlpha keep alpha channel
|
||||
*
|
||||
* @return a new {@code IndexColorModel}
|
||||
*/
|
||||
public static IndexColorModel createIndexColorModel(PixelPacket[] pColormap, boolean pAlpha) {
|
||||
int[] colors = new int[pColormap.length];
|
||||
|
||||
// TODO: Verify if this is correct for alpha...?
|
||||
int trans = pAlpha ? colors.length - 1 : -1;
|
||||
|
||||
//for (int i = 0; i < pColormap.length; i++) {
|
||||
for (int i = pColormap.length - 1; i != 0; i--) {
|
||||
PixelPacket color = pColormap[i];
|
||||
if (pAlpha) {
|
||||
colors[i] = (0xff - (color.getOpacity() & 0xff)) << 24 |
|
||||
(color.getRed() & 0xff) << 16 |
|
||||
(color.getGreen() & 0xff) << 8 |
|
||||
(color.getBlue() & 0xff);
|
||||
}
|
||||
else {
|
||||
colors[i] = (color.getRed() & 0xff) << 16 |
|
||||
(color.getGreen() & 0xff) << 8 |
|
||||
(color.getBlue() & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
return new InverseColorMapIndexColorModel(8, colors.length, colors, 0, pAlpha, trans, DataBuffer.TYPE_BYTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an (A)RGB {@code MagickImage} to a {@code BufferedImage}, of
|
||||
* type {@code TYPE_4BYTE_ABGR} or {@code TYPE_3BYTE_BGR}.
|
||||
*
|
||||
* @param pImage the original {@code MagickImage}
|
||||
* @param pAlpha keep alpha channel
|
||||
* @return a new {@code BufferedImage}
|
||||
*
|
||||
* @throws MagickException if an exception occurs during conversion
|
||||
*
|
||||
* @see BufferedImage
|
||||
*/
|
||||
private static BufferedImage rgbToBuffered(MagickImage pImage, boolean pAlpha) throws MagickException {
|
||||
Dimension size = pImage.getDimension();
|
||||
int length = size.width * size.height;
|
||||
int bands = pAlpha ? 4 : 3;
|
||||
byte[] pixels = new byte[length * bands];
|
||||
|
||||
// TODO: If we do multiple dispatches (one per line, typically), we could provide listener
|
||||
// feedback. But it's currently a lot slower than fetching all the pixels in one go.
|
||||
|
||||
// Note: The ordering ABGR or BGR corresponds to BufferedImage
|
||||
// TYPE_4BYTE_ABGR and TYPE_3BYTE_BGR respectively
|
||||
pImage.dispatchImage(0, 0, size.width, size.height, pAlpha ? "ABGR" : "BGR", pixels);
|
||||
|
||||
// Init databuffer with array, to avoid allocation of empty array
|
||||
DataBuffer buffer = new DataBufferByte(pixels, pixels.length);
|
||||
|
||||
int[] bandOffsets = pAlpha ? BAND_OFF_TRANS : BAND_OFF_OPAQUE;
|
||||
|
||||
WritableRaster raster =
|
||||
Raster.createInterleavedRaster(buffer, size.width, size.height,
|
||||
size.width * bands, bands, bandOffsets, LOCATION_UPPER_LEFT);
|
||||
|
||||
return new BufferedImage(pAlpha ? CM_COLOR_ALPHA : CM_COLOR_OPAQUE, raster, pAlpha, null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Converts an {@code MagickImage} to a {@code BufferedImage} which holds an CMYK ICC profile
|
||||
*
|
||||
* @param pImage the original {@code MagickImage}
|
||||
* @param pAlpha keep alpha channel
|
||||
* @return a new {@code BufferedImage}
|
||||
*
|
||||
* @throws MagickException if an exception occurs during conversion
|
||||
*
|
||||
* @see BufferedImage
|
||||
*/
|
||||
private static BufferedImage cmykToBuffered(MagickImage pImage, boolean pAlpha) throws MagickException {
|
||||
Dimension size = pImage.getDimension();
|
||||
int length = size.width * size.height;
|
||||
|
||||
// Retreive the ICC profile
|
||||
ICC_Profile profile = ICC_Profile.getInstance(pImage.getColorProfile().getInfo());
|
||||
ColorSpace cs = new ICC_ColorSpace(profile);
|
||||
|
||||
int bands = cs.getNumComponents() + (pAlpha ? 1 : 0);
|
||||
|
||||
int[] bits = new int[bands];
|
||||
for (int i = 0; i < bands; i++) {
|
||||
bits[i] = 8;
|
||||
}
|
||||
|
||||
ColorModel cm = pAlpha ?
|
||||
new ComponentColorModel(cs, bits, true, true, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE) :
|
||||
new ComponentColorModel(cs, bits, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
|
||||
|
||||
byte[] pixels = new byte[length * bands];
|
||||
|
||||
// TODO: If we do multiple dispatches (one per line, typically), we could provide listener
|
||||
// feedback. But it's currently a lot slower than fetching all the pixels in one go.
|
||||
// TODO: handle more generic cases if profile is not CMYK
|
||||
// TODO: Test "ACMYK"
|
||||
pImage.dispatchImage(0, 0, size.width, size.height, pAlpha ? "ACMYK" : "CMYK", pixels);
|
||||
|
||||
// Init databuffer with array, to avoid allocation of empty array
|
||||
DataBuffer buffer = new DataBufferByte(pixels, pixels.length);
|
||||
|
||||
// TODO: build array from bands variable, here it just works for CMYK
|
||||
// The values has not been tested with an alpha picture actually...
|
||||
int[] bandOffsets = pAlpha ? new int[] {0, 1, 2, 3, 4} : new int[] {0, 1, 2, 3};
|
||||
|
||||
WritableRaster raster =
|
||||
Raster.createInterleavedRaster(buffer, size.width, size.height,
|
||||
size.width * bands, bands, bandOffsets, LOCATION_UPPER_LEFT);
|
||||
|
||||
return new BufferedImage(cm, raster, pAlpha, null);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,9 @@
|
||||
package com.twelvemonkeys.image;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.*;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.*;
|
||||
|
||||
/**
|
||||
@@ -101,6 +103,15 @@ import java.awt.image.*;
|
||||
* BufferedImage scaled = new ResampleOp(w, h).filter(temp, null);
|
||||
* </pre></blockquote>
|
||||
* <p>
|
||||
* For maximum performance, this class will use native code, through
|
||||
* <a href="http://www.yeo.id.au/jmagick/">JMagick</a>, when available.
|
||||
* Otherwise, the class will silently fall back to pure Java mode.
|
||||
* Native code may be disabled globally, by setting the system property
|
||||
* {@code com.twelvemonkeys.image.accel} to {@code false}.
|
||||
* To allow debug of the native code, set the system property
|
||||
* {@code com.twelvemonkeys.image.magick.debug} to {@code true}.
|
||||
* </p>
|
||||
* <p>
|
||||
* This {@code BufferedImageOp} is based on C example code found in
|
||||
* <a href="http://www.acm.org/tog/GraphicsGems/">Graphics Gems III</a>,
|
||||
* Filtered Image Rescaling, by Dale Schumacher (with additional improvments by
|
||||
@@ -128,6 +139,9 @@ import java.awt.image.*;
|
||||
// TODO: Consider using AffineTransformOp for more operations!?
|
||||
public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
|
||||
// NOTE: These MUST correspond to ImageMagick filter types, for the
|
||||
// MagickAccelerator to work consistently (see magick.FilterType).
|
||||
|
||||
/**
|
||||
* Undefined interpolation, filter method will use default filter.
|
||||
*/
|
||||
@@ -281,10 +295,11 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
new Value(KEY_RESAMPLE_INTERPOLATION, "Blackman-Sinc", FILTER_BLACKMAN_SINC);
|
||||
|
||||
// Member variables
|
||||
private final int width;
|
||||
private final int height;
|
||||
// Package access, to allow access from MagickAccelerator
|
||||
int width;
|
||||
int height;
|
||||
|
||||
private final int filterType;
|
||||
int filterType;
|
||||
|
||||
/**
|
||||
* RendereingHints.Key implementation, works only with Value values.
|
||||
@@ -532,6 +547,16 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
// Fall through
|
||||
}
|
||||
|
||||
// Try to use native ImageMagick code
|
||||
BufferedImage result = MagickAccelerator.filter(this, input, output);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Otherwise, continue in pure Java mode
|
||||
|
||||
// TODO: What if output != null and wrong size? Create new? Render on only a part? Document?
|
||||
|
||||
// If filter type != POINT or BOX and input has IndexColorModel, convert
|
||||
// to true color, with alpha reflecting that of the original color model.
|
||||
BufferedImage temp;
|
||||
@@ -546,7 +571,7 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
|
||||
// Create or convert output to a suitable image
|
||||
// TODO: OPTIMIZE: Don't really need to convert all types to same as input
|
||||
BufferedImage result = output != null && temp.getType() != BufferedImage.TYPE_CUSTOM ? /*output*/ ImageUtil.toBuffered(output, temp.getType()) : createCompatibleDestImage(temp, null);
|
||||
result = output != null && temp.getType() != BufferedImage.TYPE_CUSTOM ? /*output*/ ImageUtil.toBuffered(output, temp.getType()) : createCompatibleDestImage(temp, null);
|
||||
|
||||
resample(temp, result, filter);
|
||||
|
||||
@@ -1255,12 +1280,12 @@ public class ResampleOp implements BufferedImageOp/* TODO: RasterOp */ {
|
||||
/*
|
||||
* image rescaling routine
|
||||
*/
|
||||
static class Contributor {
|
||||
class Contributor {
|
||||
int pixel;
|
||||
double weight;
|
||||
}
|
||||
|
||||
static class ContributorList {
|
||||
class ContributorList {
|
||||
int n;/* number of contributors (may be < p.length) */
|
||||
Contributor[] p;/* pointer to list of contributions */
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
TODO:
|
||||
Remove compile-time dependency on JMagick:
|
||||
- Extract interface for MagickAccelerator
|
||||
- Move implementation to separate module
|
||||
- Instantiate impl via reflection
|
||||
DONE:
|
||||
@@ -4,13 +4,13 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
<version>3.12.0</version>
|
||||
<version>3.9.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>common-io</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>TwelveMonkeys :: Common :: IO</name>
|
||||
<description>
|
||||
TwelveMonkeys Common I/O support classes.
|
||||
The TwelveMonkeys Common IO support
|
||||
</description>
|
||||
|
||||
<properties>
|
||||
@@ -31,12 +31,4 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
@@ -56,8 +56,8 @@ public class CompoundReader extends Reader {
|
||||
|
||||
private int currentReader;
|
||||
private int markedReader;
|
||||
private long mark;
|
||||
private long next;
|
||||
private int mark;
|
||||
private int mNext;
|
||||
|
||||
/**
|
||||
* Create a new compound reader.
|
||||
@@ -76,7 +76,7 @@ public class CompoundReader extends Reader {
|
||||
finalLock = pReaders; // NOTE: It's ok to sync on pReaders, as the
|
||||
// reference can't change, only it's elements
|
||||
|
||||
readers = new ArrayList<>();
|
||||
readers = new ArrayList<Reader>();
|
||||
|
||||
boolean markSupported = true;
|
||||
while (pReaders.hasNext()) {
|
||||
@@ -101,7 +101,7 @@ public class CompoundReader extends Reader {
|
||||
}
|
||||
|
||||
// NOTE: Reset mNext for every reader, and record marked reader in mark/reset methods!
|
||||
next = 0;
|
||||
mNext = 0;
|
||||
return current;
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ public class CompoundReader extends Reader {
|
||||
|
||||
synchronized (finalLock) {
|
||||
ensureOpen();
|
||||
mark = next;
|
||||
mark = mNext;
|
||||
markedReader = currentReader;
|
||||
|
||||
current.mark(pReadLimit);
|
||||
@@ -158,7 +158,7 @@ public class CompoundReader extends Reader {
|
||||
}
|
||||
current.reset();
|
||||
|
||||
next = mark;
|
||||
mNext = mark;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,13 +177,13 @@ public class CompoundReader extends Reader {
|
||||
return read(); // In case of 0-length readers
|
||||
}
|
||||
|
||||
next++;
|
||||
mNext++;
|
||||
|
||||
return read;
|
||||
}
|
||||
}
|
||||
|
||||
public int read(char[] pBuffer, int pOffset, int pLength) throws IOException {
|
||||
public int read(char pBuffer[], int pOffset, int pLength) throws IOException {
|
||||
synchronized (finalLock) {
|
||||
int read = current.read(pBuffer, pOffset, pLength);
|
||||
|
||||
@@ -192,7 +192,7 @@ public class CompoundReader extends Reader {
|
||||
return read(pBuffer, pOffset, pLength); // In case of 0-length readers
|
||||
}
|
||||
|
||||
next += read;
|
||||
mNext += read;
|
||||
|
||||
return read;
|
||||
}
|
||||
@@ -213,7 +213,7 @@ public class CompoundReader extends Reader {
|
||||
return skip(pChars); // In case of 0-length readers
|
||||
}
|
||||
|
||||
next += skipped;
|
||||
mNext += skipped;
|
||||
|
||||
return skipped;
|
||||
}
|
||||
|
||||
@@ -50,8 +50,8 @@ public class StringArrayReader extends StringReader {
|
||||
protected final Object finalLock;
|
||||
private int currentSting;
|
||||
private int markedString;
|
||||
private long mark;
|
||||
private long next;
|
||||
private int mark;
|
||||
private int next;
|
||||
|
||||
/**
|
||||
* Create a new string array reader.
|
||||
@@ -151,7 +151,7 @@ public class StringArrayReader extends StringReader {
|
||||
}
|
||||
}
|
||||
|
||||
public int read(char[] pBuffer, int pOffset, int pLength) throws IOException {
|
||||
public int read(char pBuffer[], int pOffset, int pLength) throws IOException {
|
||||
synchronized (finalLock) {
|
||||
int read = current.read(pBuffer, pOffset, pLength);
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ public final class SubStream extends FilterInputStream {
|
||||
*/
|
||||
public SubStream(final InputStream stream, final long length) {
|
||||
super(Validate.notNull(stream, "stream"));
|
||||
bytesLeft = Validate.isTrue(length >= 0, length, "length < 0: %s");
|
||||
bytesLeft = length;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,11 +63,10 @@ public final class SubStream extends FilterInputStream {
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
// NOTE: Do not close the underlying stream, but consume it
|
||||
// NOTE: Do not close the underlying stream
|
||||
while (bytesLeft > 0) {
|
||||
if (skip(bytesLeft) <= 0 && read() < 0) {
|
||||
break;
|
||||
}
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
skip(bytesLeft);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,7 +115,7 @@ public final class SubStream extends FilterInputStream {
|
||||
|
||||
@Override
|
||||
public long skip(long length) throws IOException {
|
||||
long skipped = super.skip(findMaxLen(length)); // Skips 0 or more, never -1
|
||||
long skipped = super.skip(findMaxLen(length));// Skips 0 or more, never -1
|
||||
bytesLeft -= skipped;
|
||||
|
||||
return skipped;
|
||||
|
||||
@@ -59,7 +59,7 @@ public final class DecoderStream extends FilterInputStream {
|
||||
* @see java.io.FilterInputStream#in
|
||||
*/
|
||||
public DecoderStream(final InputStream stream, final Decoder decoder) {
|
||||
// TODO: Let the decoder decide preferred buffer size
|
||||
// TODO: Let the decoder decide preferred buffer size
|
||||
this(stream, decoder, 1024);
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ public final class DecoderStream extends FilterInputStream {
|
||||
super(stream);
|
||||
|
||||
this.decoder = decoder;
|
||||
buffer = ByteBuffer.allocate(bufferSize); // TODO: Allow decoder to specify minimum buffer size
|
||||
buffer = ByteBuffer.allocate(bufferSize);
|
||||
buffer.flip();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
package com.twelvemonkeys.io;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Random;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* SubStreamTest.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: SubStreamTest.java,v 1.0 07/11/2023 haraldk Exp$
|
||||
*/
|
||||
public class SubStreamTest {
|
||||
|
||||
private final Random rng = new Random(2918475687L);
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testCreateNullStream() {
|
||||
new SubStream(null, 42);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testCreateNegativeLength() {
|
||||
new SubStream(new ByteArrayInputStream(new byte[1]), -1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadAll() throws IOException {
|
||||
byte[] buf = new byte[128];
|
||||
rng.nextBytes(buf);
|
||||
|
||||
try (InputStream stream = new SubStream(new ByteArrayInputStream(buf), buf.length)) {
|
||||
for (byte b : buf) {
|
||||
assertEquals(b, (byte) stream.read());
|
||||
}
|
||||
|
||||
assertEquals(-1, stream.read());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadAllArray() throws IOException {
|
||||
byte[] buf = new byte[128];
|
||||
rng.nextBytes(buf);
|
||||
|
||||
try (InputStream stream = new SubStream(new ByteArrayInputStream(buf), buf.length)) {
|
||||
byte[] temp = new byte[buf.length / 4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
assertEquals(temp.length, stream.read(temp)); // Depends on ByteArrayInputStream specifics...
|
||||
assertArrayEquals(Arrays.copyOfRange(buf, i * temp.length, (i + 1) * temp.length), temp);
|
||||
}
|
||||
|
||||
assertEquals(-1, stream.read());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipAll() throws IOException {
|
||||
byte[] buf = new byte[128];
|
||||
|
||||
try (InputStream stream = new SubStream(new ByteArrayInputStream(buf), buf.length)) {
|
||||
assertEquals(128, stream.skip(buf.length)); // Depends on ByteArrayInputStream specifics...
|
||||
assertEquals(-1, stream.read());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("EmptyTryBlock")
|
||||
@Test
|
||||
public void testCloseConsumesAll() throws IOException {
|
||||
ByteArrayInputStream stream = new ByteArrayInputStream(new byte[128]);
|
||||
|
||||
try (InputStream ignore = new SubStream(stream, 128)) {
|
||||
// Nothing here...
|
||||
}
|
||||
|
||||
assertEquals(0, stream.available());
|
||||
assertEquals(-1, stream.read());
|
||||
}
|
||||
|
||||
@SuppressWarnings("EmptyTryBlock")
|
||||
@Test
|
||||
public void testCloseConsumesAllLongStream() throws IOException {
|
||||
ByteArrayInputStream stream = new ByteArrayInputStream(new byte[256]);
|
||||
|
||||
try (InputStream ignore = new SubStream(stream, 128)) {
|
||||
// Nothing here...
|
||||
}
|
||||
|
||||
assertEquals(128, stream.available());
|
||||
assertEquals(0, stream.read());
|
||||
}
|
||||
|
||||
@SuppressWarnings("EmptyTryBlock")
|
||||
@Test(timeout = 500L)
|
||||
public void testCloseConsumesAllShortStream() throws IOException {
|
||||
ByteArrayInputStream stream = new ByteArrayInputStream(new byte[13]);
|
||||
|
||||
try (InputStream ignore = new SubStream(stream, 42)) {
|
||||
// Nothing here...
|
||||
}
|
||||
|
||||
assertEquals(0, stream.available());
|
||||
assertEquals(-1, stream.read());
|
||||
}
|
||||
}
|
||||
@@ -4,25 +4,17 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
<version>3.12.0</version>
|
||||
<version>3.9.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>common-lang</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>TwelveMonkeys :: Common :: Language support</name>
|
||||
<description>
|
||||
TwelveMonkeys Common language support classes.
|
||||
The TwelveMonkeys Common Language support
|
||||
</description>
|
||||
|
||||
<properties>
|
||||
<project.jpms.module.name>com.twelvemonkeys.common.lang</project.jpms.module.name>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys</groupId>
|
||||
<artifactId>twelvemonkeys</artifactId>
|
||||
<version>3.12.0</version>
|
||||
<version>3.9.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>com.twelvemonkeys.common</groupId>
|
||||
<artifactId>common</artifactId>
|
||||
|
||||
+2
-11
@@ -4,13 +4,13 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys</groupId>
|
||||
<artifactId>twelvemonkeys</artifactId>
|
||||
<version>3.12.0</version>
|
||||
<version>3.9.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>com.twelvemonkeys.contrib</groupId>
|
||||
<artifactId>contrib</artifactId>
|
||||
<name>TwelveMonkeys :: Contrib</name>
|
||||
<description>
|
||||
Contributions to TwelveMonkeys and code that doesn't fit anywhere else.
|
||||
Contributions to TwelveMonkeys which are not matching into the ImageIO plug-ins.
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
@@ -69,13 +69,4 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.12.0</version>
|
||||
<version>3.9.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>imageio-batik</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: Batik Plugin</name>
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
<properties>
|
||||
<project.jpms.module.name>com.twelvemonkeys.imageio.batik</project.jpms.module.name>
|
||||
<batik.version>1.17</batik.version>
|
||||
<batik.version>1.16</batik.version>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
@@ -33,18 +33,6 @@
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Provide-Capability>
|
||||
osgi.serviceloader;
|
||||
osgi.serviceloader=javax.imageio.spi.ImageReaderSpi
|
||||
</Provide-Capability>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
@@ -63,7 +51,7 @@
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.17.0</version>
|
||||
<version>2.13.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
+32
-34
@@ -33,7 +33,6 @@ package com.twelvemonkeys.imageio.plugins.svg;
|
||||
import com.twelvemonkeys.image.ImageUtil;
|
||||
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
|
||||
import org.apache.batik.anim.dom.SVGDOMImplementation;
|
||||
@@ -92,10 +91,10 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
/**
|
||||
* Creates an {@code SVGImageReader}.
|
||||
*
|
||||
* @param provider the provider
|
||||
* @param pProvider the provider
|
||||
*/
|
||||
public SVGImageReader(final ImageReaderSpi provider) {
|
||||
super(provider);
|
||||
public SVGImageReader(final ImageReaderSpi pProvider) {
|
||||
super(pProvider);
|
||||
}
|
||||
|
||||
protected void resetMembers() {
|
||||
@@ -109,20 +108,20 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) {
|
||||
super.setInput(input, seekForwardOnly, ignoreMetadata);
|
||||
public void setInput(Object pInput, boolean seekForwardOnly, boolean ignoreMetadata) {
|
||||
super.setInput(pInput, seekForwardOnly, ignoreMetadata);
|
||||
|
||||
if (imageInput != null) {
|
||||
TranscoderInput transcoderInput = new TranscoderInput(IIOUtil.createStreamAdapter(imageInput));
|
||||
rasterizer.setInput(transcoderInput);
|
||||
TranscoderInput input = new TranscoderInput(IIOUtil.createStreamAdapter(imageInput));
|
||||
rasterizer.setInput(input);
|
||||
}
|
||||
}
|
||||
|
||||
public BufferedImage read(int imageIndex, ImageReadParam param) throws IOException {
|
||||
checkBounds(imageIndex);
|
||||
public BufferedImage read(int pIndex, ImageReadParam pParam) throws IOException {
|
||||
checkBounds(pIndex);
|
||||
|
||||
if (param instanceof SVGReadParam) {
|
||||
SVGReadParam svgParam = (SVGReadParam) param;
|
||||
if (pParam instanceof SVGReadParam) {
|
||||
SVGReadParam svgParam = (SVGReadParam) pParam;
|
||||
|
||||
// set the external-resource-resolution preference
|
||||
allowExternalResources = svgParam.isAllowExternalResources();
|
||||
@@ -140,17 +139,17 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
}
|
||||
|
||||
Dimension size = null;
|
||||
if (param != null) {
|
||||
size = param.getSourceRenderSize();
|
||||
if (pParam != null) {
|
||||
size = pParam.getSourceRenderSize();
|
||||
}
|
||||
if (size == null) {
|
||||
size = new Dimension(getWidth(imageIndex), getHeight(imageIndex));
|
||||
size = new Dimension(getWidth(pIndex), getHeight(pIndex));
|
||||
}
|
||||
|
||||
BufferedImage destination = getDestination(param, getImageTypes(imageIndex), size.width, size.height);
|
||||
BufferedImage destination = getDestination(pParam, getImageTypes(pIndex), size.width, size.height);
|
||||
|
||||
// Read in the image, using the Batik Transcoder
|
||||
processImageStarted(imageIndex);
|
||||
processImageStarted(pIndex);
|
||||
|
||||
BufferedImage image = rasterizer.getImage();
|
||||
|
||||
@@ -174,18 +173,18 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
return ex.getException() != null ? ex.getException() : ex;
|
||||
}
|
||||
|
||||
private TranscodingHints paramsToHints(SVGReadParam param) throws IOException {
|
||||
private TranscodingHints paramsToHints(SVGReadParam pParam) throws IOException {
|
||||
TranscodingHints hints = new TranscodingHints();
|
||||
// Note: We must allow generic ImageReadParams, so converting to
|
||||
// TanscodingHints should be done outside the SVGReadParam class.
|
||||
|
||||
// Set dimensions
|
||||
Dimension size = param.getSourceRenderSize();
|
||||
Dimension size = pParam.getSourceRenderSize();
|
||||
Rectangle viewBox = rasterizer.getViewBox();
|
||||
if (size == null) {
|
||||
// SVG is not a pixel based format, but we'll scale it, according to
|
||||
// the subsampling for compatibility
|
||||
size = getSourceRenderSizeFromSubsamping(param, viewBox.getSize());
|
||||
size = getSourceRenderSizeFromSubsamping(pParam, viewBox.getSize());
|
||||
}
|
||||
|
||||
if (size != null) {
|
||||
@@ -194,7 +193,7 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
}
|
||||
|
||||
// Set area of interest
|
||||
Rectangle region = param.getSourceRegion();
|
||||
Rectangle region = pParam.getSourceRegion();
|
||||
if (region != null) {
|
||||
hints.put(ImageTranscoder.KEY_AOI, region);
|
||||
|
||||
@@ -218,7 +217,7 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
}
|
||||
|
||||
// Background color
|
||||
Paint bg = param.getBackgroundColor();
|
||||
Paint bg = pParam.getBackgroundColor();
|
||||
if (bg != null) {
|
||||
hints.put(ImageTranscoder.KEY_BACKGROUND_COLOR, bg);
|
||||
}
|
||||
@@ -226,10 +225,10 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
return hints;
|
||||
}
|
||||
|
||||
private Dimension getSourceRenderSizeFromSubsamping(ImageReadParam param, Dimension origSize) {
|
||||
if (param.getSourceXSubsampling() > 1 || param.getSourceYSubsampling() > 1) {
|
||||
return new Dimension((int) (origSize.width / (float) param.getSourceXSubsampling()),
|
||||
(int) (origSize.height / (float) param.getSourceYSubsampling()));
|
||||
private Dimension getSourceRenderSizeFromSubsamping(ImageReadParam pParam, Dimension pOrigSize) {
|
||||
if (pParam.getSourceXSubsampling() > 1 || pParam.getSourceYSubsampling() > 1) {
|
||||
return new Dimension((int) (pOrigSize.width / (float) pParam.getSourceXSubsampling()),
|
||||
(int) (pOrigSize.height / (float) pParam.getSourceYSubsampling()));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -238,19 +237,19 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
return new SVGReadParam();
|
||||
}
|
||||
|
||||
public int getWidth(int imageIndex) throws IOException {
|
||||
checkBounds(imageIndex);
|
||||
public int getWidth(int pIndex) throws IOException {
|
||||
checkBounds(pIndex);
|
||||
|
||||
return rasterizer.getDefaultWidth();
|
||||
}
|
||||
|
||||
public int getHeight(int imageIndex) throws IOException {
|
||||
checkBounds(imageIndex);
|
||||
public int getHeight(int pIndex) throws IOException {
|
||||
checkBounds(pIndex);
|
||||
return rasterizer.getDefaultHeight();
|
||||
}
|
||||
|
||||
public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) {
|
||||
return Collections.singleton(ImageTypeSpecifiers.createFromRenderedImage(rasterizer.createImage(1, 1))).iterator();
|
||||
return Collections.singleton(ImageTypeSpecifier.createFromRenderedImage(rasterizer.createImage(1, 1))).iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -602,7 +601,6 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
initialized = true;
|
||||
|
||||
try {
|
||||
super.addTranscodingHint(SVGAbstractTranscoder.KEY_ALLOW_EXTERNAL_RESOURCES, allowExternalResources);
|
||||
super.transcode(transcoderInput, null);
|
||||
}
|
||||
catch (TranscoderException e) {
|
||||
@@ -635,8 +633,8 @@ public class SVGImageReader extends ImageReaderBase {
|
||||
return viewBox.getBounds();
|
||||
}
|
||||
|
||||
void setInput(final TranscoderInput input) {
|
||||
transcoderInput = input;
|
||||
void setInput(final TranscoderInput pInput) {
|
||||
transcoderInput = pInput;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+14
-14
@@ -60,22 +60,22 @@ public final class SVGImageReaderSpi extends ImageReaderSpiBase {
|
||||
super(new SVGProviderInfo());
|
||||
}
|
||||
|
||||
public boolean canDecodeInput(final Object source) throws IOException {
|
||||
return source instanceof ImageInputStream && canDecode((ImageInputStream) source);
|
||||
public boolean canDecodeInput(final Object pSource) throws IOException {
|
||||
return pSource instanceof ImageInputStream && canDecode((ImageInputStream) pSource);
|
||||
}
|
||||
|
||||
@SuppressWarnings("StatementWithEmptyBody")
|
||||
private static boolean canDecode(final ImageInputStream input) throws IOException {
|
||||
private static boolean canDecode(final ImageInputStream pInput) throws IOException {
|
||||
// NOTE: This test is quite quick as it does not involve any parsing,
|
||||
// however it may not recognize all kinds of SVG documents.
|
||||
try {
|
||||
input.mark();
|
||||
pInput.mark();
|
||||
|
||||
// TODO: This is not ok for UTF-16 and other wide encodings
|
||||
// TODO: Use an XML (encoding) aware Reader instance instead
|
||||
// Need to figure out pretty fast if this is XML or not
|
||||
int b;
|
||||
while (Character.isWhitespace((char) (b = input.read()))) {
|
||||
while (Character.isWhitespace((char) (b = pInput.read()))) {
|
||||
// Skip over leading WS
|
||||
}
|
||||
|
||||
@@ -95,30 +95,30 @@ public final class SVGImageReaderSpi extends ImageReaderSpiBase {
|
||||
|
||||
byte[] buffer = new byte[4];
|
||||
while (true) {
|
||||
input.readFully(buffer);
|
||||
pInput.readFully(buffer);
|
||||
|
||||
if (buffer[0] == '?') {
|
||||
// This is the XML declaration or a processing instruction
|
||||
while (!((input.readByte() & 0xFF) == '?' && input.read() == '>')) {
|
||||
while (!((pInput.readByte() & 0xFF) == '?' && pInput.read() == '>')) {
|
||||
// Skip until end of XML declaration or processing instruction or EOF
|
||||
}
|
||||
}
|
||||
else if (buffer[0] == '!') {
|
||||
if (buffer[1] == '-' && buffer[2] == '-') {
|
||||
// This is a comment
|
||||
while (!((input.readByte() & 0xFF) == '-' && input.read() == '-' && input.read() == '>')) {
|
||||
while (!((pInput.readByte() & 0xFF) == '-' && pInput.read() == '-' && pInput.read() == '>')) {
|
||||
// Skip until end of comment or EOF
|
||||
}
|
||||
}
|
||||
else if (buffer[1] == 'D' && buffer[2] == 'O' && buffer[3] == 'C'
|
||||
&& input.read() == 'T' && input.read() == 'Y'
|
||||
&& input.read() == 'P' && input.read() == 'E') {
|
||||
&& pInput.read() == 'T' && pInput.read() == 'Y'
|
||||
&& pInput.read() == 'P' && pInput.read() == 'E') {
|
||||
// This is the DOCTYPE declaration
|
||||
while (Character.isWhitespace((char) (b = input.read()))) {
|
||||
while (Character.isWhitespace((char) (b = pInput.read()))) {
|
||||
// Skip over WS
|
||||
}
|
||||
|
||||
if (b == 's' && input.read() == 'v' && input.read() == 'g') {
|
||||
if (b == 's' && pInput.read() == 'v' && pInput.read() == 'g') {
|
||||
// It's SVG, identified by DOCTYPE
|
||||
return true;
|
||||
}
|
||||
@@ -142,7 +142,7 @@ public final class SVGImageReaderSpi extends ImageReaderSpiBase {
|
||||
return false;
|
||||
}
|
||||
|
||||
while ((input.readByte() & 0xFF) != '<') {
|
||||
while ((pInput.readByte() & 0xFF) != '<') {
|
||||
// Skip over, until next begin tag or EOF
|
||||
}
|
||||
}
|
||||
@@ -153,7 +153,7 @@ public final class SVGImageReaderSpi extends ImageReaderSpiBase {
|
||||
}
|
||||
finally {
|
||||
//noinspection ThrowFromFinallyBlock
|
||||
input.reset();
|
||||
pInput.reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -51,16 +51,16 @@ public class SVGReadParam extends ImageReadParam {
|
||||
return background;
|
||||
}
|
||||
|
||||
public void setBackgroundColor(Paint color) {
|
||||
background = color;
|
||||
public void setBackgroundColor(Paint pColor) {
|
||||
background = pColor;
|
||||
}
|
||||
|
||||
public String getBaseURI() {
|
||||
return baseURI;
|
||||
}
|
||||
|
||||
public void setBaseURI(String baseURI) {
|
||||
this.baseURI = baseURI;
|
||||
public void setBaseURI(String pBaseURI) {
|
||||
baseURI = pBaseURI;
|
||||
}
|
||||
|
||||
public void setAllowExternalResources(boolean allow) {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.12.0</version>
|
||||
<version>3.9.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>imageio-bmp</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: BMP plugin</name>
|
||||
@@ -26,23 +26,4 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Provide-Capability>
|
||||
osgi.serviceloader;
|
||||
osgi.serviceloader=javax.imageio.spi.ImageReaderSpi,
|
||||
osgi.serviceloader;
|
||||
osgi.serviceloader=javax.imageio.spi.ImageWriterSpi
|
||||
</Provide-Capability>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
+13
-14
@@ -81,8 +81,8 @@ public final class BMPImageReader extends ImageReaderBase {
|
||||
super(new BMPImageReaderSpi());
|
||||
}
|
||||
|
||||
BMPImageReader(final ImageReaderSpi provider) {
|
||||
super(provider);
|
||||
BMPImageReader(final ImageReaderSpi pProvider) {
|
||||
super(pProvider);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -129,7 +129,6 @@ public final class BMPImageReader extends ImageReaderBase {
|
||||
|
||||
// Read DIB header
|
||||
header = DIBHeader.read(imageInput);
|
||||
// System.out.println("header = " + header);
|
||||
|
||||
if (pixelOffset < header.size + DIB.BMP_FILE_HEADER_SIZE) {
|
||||
throw new IIOException("Invalid pixel offset: " + pixelOffset);
|
||||
@@ -187,30 +186,30 @@ public final class BMPImageReader extends ImageReaderBase {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth(int imageIndex) throws IOException {
|
||||
checkBounds(imageIndex);
|
||||
public int getWidth(int pImageIndex) throws IOException {
|
||||
checkBounds(pImageIndex);
|
||||
|
||||
return header.getWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight(int imageIndex) throws IOException {
|
||||
checkBounds(imageIndex);
|
||||
public int getHeight(int pImageIndex) throws IOException {
|
||||
checkBounds(pImageIndex);
|
||||
|
||||
return header.getHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IOException {
|
||||
checkBounds(imageIndex);
|
||||
public Iterator<ImageTypeSpecifier> getImageTypes(int pImageIndex) throws IOException {
|
||||
checkBounds(pImageIndex);
|
||||
|
||||
// TODO: Better implementation, include INT_RGB types for 3BYTE_BGR and 4BYTE_ABGR for INT_ARGB
|
||||
return Collections.singletonList(getRawImageType(imageIndex)).iterator();
|
||||
return Collections.singletonList(getRawImageType(pImageIndex)).iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageTypeSpecifier getRawImageType(int imageIndex) throws IOException {
|
||||
checkBounds(imageIndex);
|
||||
public ImageTypeSpecifier getRawImageType(int pImageIndex) throws IOException {
|
||||
checkBounds(pImageIndex);
|
||||
|
||||
if (header.getPlanes() != 1) {
|
||||
throw new IIOException("Multiple planes not supported");
|
||||
@@ -686,8 +685,8 @@ public final class BMPImageReader extends ImageReaderBase {
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "UnusedDeclaration", "SameParameterValue" })
|
||||
static <T extends Throwable> void throwAs(final Class<T> type, final Throwable throwable) throws T {
|
||||
throw (T) throwable;
|
||||
static <T extends Throwable> void throwAs(final Class<T> pType, final Throwable pThrowable) throws T {
|
||||
throw (T) pThrowable;
|
||||
}
|
||||
|
||||
private class ListenerDelegator extends ProgressListenerBase implements IIOReadUpdateListener, IIOReadWarningListener {
|
||||
|
||||
+8
-8
@@ -65,16 +65,16 @@ public final class BMPImageReaderSpi extends ImageReaderSpiBase {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canDecodeInput(final Object source) throws IOException {
|
||||
return source instanceof ImageInputStream && canDecode((ImageInputStream) source);
|
||||
public boolean canDecodeInput(final Object pSource) throws IOException {
|
||||
return pSource instanceof ImageInputStream && canDecode((ImageInputStream) pSource);
|
||||
}
|
||||
|
||||
private static boolean canDecode(final ImageInputStream input) throws IOException {
|
||||
private static boolean canDecode(final ImageInputStream pInput) throws IOException {
|
||||
byte[] fileHeader = new byte[18]; // Strictly: file header (14 bytes) + BMP header size field (4 bytes)
|
||||
|
||||
try {
|
||||
input.mark();
|
||||
input.readFully(fileHeader);
|
||||
pInput.mark();
|
||||
pInput.readFully(fileHeader);
|
||||
|
||||
// Magic: BM
|
||||
if (fileHeader[0] != 'B' || fileHeader[1] != 'M') {
|
||||
@@ -112,15 +112,15 @@ public final class BMPImageReaderSpi extends ImageReaderSpiBase {
|
||||
}
|
||||
}
|
||||
finally {
|
||||
input.reset();
|
||||
pInput.reset();
|
||||
}
|
||||
}
|
||||
|
||||
public ImageReader createReaderInstance(final Object extension) {
|
||||
public ImageReader createReaderInstance(final Object pExtension) {
|
||||
return new BMPImageReader(this);
|
||||
}
|
||||
|
||||
public String getDescription(final Locale locale) {
|
||||
public String getDescription(final Locale pLocale) {
|
||||
return "Windows Device Independent Bitmap Format (BMP) Reader";
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ import java.nio.ByteOrder;
|
||||
* BMPImageWriter
|
||||
*/
|
||||
public final class BMPImageWriter extends DIBImageWriter {
|
||||
BMPImageWriter(ImageWriterSpi provider) {
|
||||
protected BMPImageWriter(ImageWriterSpi provider) {
|
||||
super(provider);
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -32,7 +32,6 @@ package com.twelvemonkeys.imageio.plugins.bmp;
|
||||
|
||||
import com.twelvemonkeys.imageio.AbstractMetadata;
|
||||
import com.twelvemonkeys.lang.Validate;
|
||||
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import javax.imageio.metadata.IIOMetadataNode;
|
||||
@@ -142,7 +141,7 @@ final class BMPMetadata extends AbstractMetadata {
|
||||
@Override
|
||||
protected IIOMetadataNode getStandardChromaNode() {
|
||||
// NOTE: BMP files may contain a color map, even if true color...
|
||||
// Not sure if this is a good idea to expose to the metadata,
|
||||
// Not sure if this is a good idea to expose to the meta data,
|
||||
// as it might be unexpected... Then again...
|
||||
if (colorMap != null) {
|
||||
IIOMetadataNode chroma = new IIOMetadataNode("Chroma");
|
||||
|
||||
+7
-7
@@ -29,11 +29,11 @@
|
||||
*/
|
||||
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||
|
||||
import java.awt.image.*;
|
||||
import java.io.IOException;
|
||||
|
||||
import static com.twelvemonkeys.lang.Validate.notNull;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Describes a bitmap structure.
|
||||
*
|
||||
@@ -47,9 +47,9 @@ abstract class BitmapDescriptor {
|
||||
protected BufferedImage image;
|
||||
protected BitmapMask mask;
|
||||
|
||||
public BitmapDescriptor(final DirectoryEntry entry, final DIBHeader header) {
|
||||
this.entry = notNull(entry, "entry");
|
||||
this.header = notNull(header, "header");
|
||||
public BitmapDescriptor(final DirectoryEntry pEntry, final DIBHeader pHeader) {
|
||||
entry = notNull(pEntry, "entry");;
|
||||
header = notNull(pHeader, "header");
|
||||
}
|
||||
|
||||
abstract public BufferedImage getImage() throws IOException;
|
||||
@@ -75,7 +75,7 @@ abstract class BitmapDescriptor {
|
||||
return getClass().getSimpleName() + "[" + entry + ", " + header + "]";
|
||||
}
|
||||
|
||||
final void setMask(final BitmapMask mask) {
|
||||
public final void setMask(final BitmapMask mask) {
|
||||
this.mask = mask;
|
||||
}
|
||||
|
||||
|
||||
+22
-14
@@ -29,7 +29,10 @@
|
||||
*/
|
||||
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||
|
||||
import java.awt.image.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.awt.image.IndexColorModel;
|
||||
import java.awt.image.WritableRaster;
|
||||
import java.util.Hashtable;
|
||||
|
||||
/**
|
||||
@@ -38,13 +41,12 @@ import java.util.Hashtable;
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: BitmapIndexed.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
|
||||
*/
|
||||
final class BitmapIndexed extends BitmapDescriptor {
|
||||
final int[] bits;
|
||||
final int[] colors;
|
||||
|
||||
public BitmapIndexed(final DirectoryEntry entry, final DIBHeader header) {
|
||||
super(entry, header);
|
||||
class BitmapIndexed extends BitmapDescriptor {
|
||||
protected final int[] bits;
|
||||
protected final int[] colors;
|
||||
|
||||
public BitmapIndexed(final DirectoryEntry pEntry, final DIBHeader pHeader) {
|
||||
super(pEntry, pHeader);
|
||||
bits = new int[getWidth() * getHeight()];
|
||||
|
||||
// NOTE: We're adding space for one extra color, for transparency
|
||||
@@ -57,16 +59,20 @@ final class BitmapIndexed extends BitmapDescriptor {
|
||||
|
||||
IndexColorModel icm = createColorModel();
|
||||
|
||||
// We add cursor hotspot as a property to images created from CUR format.
|
||||
// This is slightly obscure, and should probably be moved...
|
||||
// This is slightly obscure, and should probably be moved..
|
||||
Hashtable<String, Object> properties = null;
|
||||
if (entry instanceof DirectoryEntry.CUREntry) {
|
||||
properties = new Hashtable<>(1);
|
||||
properties.put("cursor_hotspot", ((DirectoryEntry.CUREntry) this.entry).getHotspot());
|
||||
}
|
||||
|
||||
WritableRaster raster = icm.createCompatibleWritableRaster(getWidth(), getHeight());
|
||||
BufferedImage image = new BufferedImage(icm, raster, icm.isAlphaPremultiplied(), properties);
|
||||
BufferedImage image = new BufferedImage(
|
||||
icm,
|
||||
icm.createCompatibleWritableRaster(getWidth(), getHeight()),
|
||||
icm.isAlphaPremultiplied(), properties
|
||||
);
|
||||
|
||||
WritableRaster raster = image.getRaster();
|
||||
|
||||
// Make pixels transparent according to mask
|
||||
final int trans = icm.getTransparentPixel();
|
||||
@@ -99,7 +105,7 @@ final class BitmapIndexed extends BitmapDescriptor {
|
||||
int index = findTransparentIndexMaybeRemap(this.colors, this.bits);
|
||||
|
||||
if (index == -1) {
|
||||
// No duplicate found, increase bit count
|
||||
// No duplicate found, increase bitcount
|
||||
bits++;
|
||||
transparent = this.colors.length - 1;
|
||||
}
|
||||
@@ -111,8 +117,10 @@ final class BitmapIndexed extends BitmapDescriptor {
|
||||
}
|
||||
|
||||
// NOTE: Setting hasAlpha to true, makes things work on 1.2
|
||||
return new IndexColorModel(bits, colors, this.colors, 0, true, transparent,
|
||||
bits <= 8 ? DataBuffer.TYPE_BYTE : DataBuffer.TYPE_USHORT);
|
||||
return new IndexColorModel(
|
||||
bits, colors, this.colors, 0, true, transparent,
|
||||
bits <= 8 ? DataBuffer.TYPE_BYTE : DataBuffer.TYPE_USHORT
|
||||
);
|
||||
}
|
||||
|
||||
private static int findTransparentIndexMaybeRemap(final int[] colors, final int[] bits) {
|
||||
|
||||
+8
-8
@@ -30,7 +30,7 @@
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||
|
||||
import java.awt.image.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
|
||||
/**
|
||||
@@ -39,17 +39,17 @@ import java.awt.image.*;
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: BitmapMask.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
|
||||
*/
|
||||
final class BitmapMask extends BitmapDescriptor {
|
||||
final BitmapIndexed bitMask;
|
||||
class BitmapMask extends BitmapDescriptor {
|
||||
protected final BitmapIndexed bitMask;
|
||||
|
||||
public BitmapMask(final DirectoryEntry parent, final DIBHeader header) {
|
||||
super(parent, header);
|
||||
bitMask = new BitmapIndexed(parent, header);
|
||||
public BitmapMask(final DirectoryEntry pParent, final DIBHeader pHeader) {
|
||||
super(pParent, pHeader);
|
||||
bitMask = new BitmapIndexed(pParent, pHeader);
|
||||
}
|
||||
|
||||
boolean isTransparent(final int x, final int y) {
|
||||
boolean isTransparent(final int pX, final int pY) {
|
||||
// NOTE: 1: Fully transparent, 0: Opaque...
|
||||
return bitMask.bits[x + y * getWidth()] != 0;
|
||||
return bitMask.bits[pX + pY * getWidth()] != 0;
|
||||
}
|
||||
|
||||
public BufferedImage getImage() {
|
||||
|
||||
+6
-5
@@ -31,7 +31,8 @@
|
||||
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.WritableRaster;
|
||||
|
||||
/**
|
||||
* Describes an RGB/true color bitmap structure (16, 24 and 32 bits per pixel).
|
||||
@@ -39,10 +40,10 @@ import java.awt.image.*;
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: BitmapRGB.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
|
||||
*/
|
||||
final class BitmapRGB extends BitmapDescriptor {
|
||||
class BitmapRGB extends BitmapDescriptor {
|
||||
|
||||
public BitmapRGB(final DirectoryEntry entry, final DIBHeader header) {
|
||||
super(entry, header);
|
||||
public BitmapRGB(final DirectoryEntry pEntry, final DIBHeader pHeader) {
|
||||
super(pEntry, pHeader);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -70,7 +71,7 @@ final class BitmapRGB extends BitmapDescriptor {
|
||||
|
||||
WritableRaster alphaRaster = masked.getAlphaRaster();
|
||||
|
||||
byte[] trans = {0x00};
|
||||
byte[] trans = {0x0};
|
||||
for (int y = 0; y < getHeight(); y++) {
|
||||
for (int x = 0; x < getWidth(); x++) {
|
||||
if (mask.isTransparent(x, y)) {
|
||||
|
||||
+8
-7
@@ -30,10 +30,11 @@
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import java.awt.image.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
|
||||
/**
|
||||
* Represents bitmap structures we can't read.
|
||||
* Allows for deferred exception handling, and allowing clients to read all images that can be read.
|
||||
@@ -41,13 +42,13 @@ import java.io.IOException;
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @version $Id: BitmapUnsupported.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
|
||||
*/
|
||||
final class BitmapUnsupported extends BitmapDescriptor {
|
||||
private final String message;
|
||||
class BitmapUnsupported extends BitmapDescriptor {
|
||||
private String message;
|
||||
|
||||
public BitmapUnsupported(final DirectoryEntry entry, DIBHeader header, final String message) {
|
||||
super(entry, header);
|
||||
public BitmapUnsupported(final DirectoryEntry pEntry, DIBHeader header, final String pMessage) {
|
||||
super(pEntry, header);
|
||||
|
||||
this.message = message;
|
||||
message = pMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+5
-5
@@ -48,22 +48,22 @@ public final class CURImageReader extends DIBImageReader {
|
||||
super(new CURImageReaderSpi());
|
||||
}
|
||||
|
||||
CURImageReader(final ImageReaderSpi provider) {
|
||||
super(provider);
|
||||
protected CURImageReader(final ImageReaderSpi pProvider) {
|
||||
super(pProvider);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hot spot location for the cursor.
|
||||
*
|
||||
* @param imageIndex the index of the cursor in the current input.
|
||||
* @param pImageIndex the index of the cursor in the current input.
|
||||
* @return the hot spot location for the cursor
|
||||
*
|
||||
* @throws java.io.IOException if an I/O exception occurs during reading of image meta data
|
||||
* @throws IndexOutOfBoundsException if {@code pImageIndex} is less than {@code 0} or greater than/equal to
|
||||
* the number of cursors in the file
|
||||
*/
|
||||
public Point getHotSpot(final int imageIndex) throws IOException {
|
||||
DirectoryEntry.CUREntry entry = (DirectoryEntry.CUREntry) getEntry(imageIndex);
|
||||
public final Point getHotSpot(final int pImageIndex) throws IOException {
|
||||
DirectoryEntry.CUREntry entry = (DirectoryEntry.CUREntry) getEntry(pImageIndex);
|
||||
return entry.getHotspot();
|
||||
}
|
||||
}
|
||||
|
||||
+5
-4
@@ -32,6 +32,7 @@ package com.twelvemonkeys.imageio.plugins.bmp;
|
||||
|
||||
import com.twelvemonkeys.imageio.spi.ImageReaderSpiBase;
|
||||
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
@@ -48,15 +49,15 @@ public final class CURImageReaderSpi extends ImageReaderSpiBase {
|
||||
super(new CURProviderInfo());
|
||||
}
|
||||
|
||||
public boolean canDecodeInput(final Object source) throws IOException {
|
||||
return source instanceof ImageInputStream && ICOImageReaderSpi.canDecode((ImageInputStream) source, DIB.TYPE_CUR);
|
||||
public boolean canDecodeInput(final Object pSource) throws IOException {
|
||||
return pSource instanceof ImageInputStream && ICOImageReaderSpi.canDecode((ImageInputStream) pSource, DIB.TYPE_CUR);
|
||||
}
|
||||
|
||||
public CURImageReader createReaderInstance(final Object extension) {
|
||||
public ImageReader createReaderInstance(final Object pExtension) throws IOException {
|
||||
return new CURImageReader(this);
|
||||
}
|
||||
|
||||
public String getDescription(final Locale locale) {
|
||||
public String getDescription(final Locale pLocale) {
|
||||
return "Windows Cursor Format (CUR) Reader";
|
||||
}
|
||||
}
|
||||
|
||||
+103
-171
@@ -30,11 +30,12 @@
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
|
||||
/**
|
||||
* Represents the DIB (Device Independent Bitmap) Information header structure.
|
||||
*
|
||||
@@ -90,17 +91,17 @@ abstract class DIBHeader {
|
||||
protected DIBHeader() {
|
||||
}
|
||||
|
||||
public static DIBHeader read(final DataInput stream) throws IOException {
|
||||
int size = stream.readInt();
|
||||
public static DIBHeader read(final DataInput pStream) throws IOException {
|
||||
int size = pStream.readInt();
|
||||
|
||||
DIBHeader header = createHeader(size);
|
||||
header.read(size, stream);
|
||||
header.read(size, pStream);
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
private static DIBHeader createHeader(final int size) throws IOException {
|
||||
switch (size) {
|
||||
private static DIBHeader createHeader(final int pSize) throws IOException {
|
||||
switch (pSize) {
|
||||
case DIB.BITMAP_CORE_HEADER_SIZE:
|
||||
return new BitmapCoreHeader();
|
||||
case DIB.OS2_V2_HEADER_16_SIZE:
|
||||
@@ -117,12 +118,11 @@ abstract class DIBHeader {
|
||||
case DIB.BITMAP_V5_INFO_HEADER_SIZE:
|
||||
return new BitmapV5InfoHeader();
|
||||
default:
|
||||
throw new IIOException(String.format("Unknown Bitmap Information Header (size: %s)", size));
|
||||
throw new IIOException(String.format("Unknown Bitmap Information Header (size: %s)", pSize));
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void read(int size, DataInput stream) throws IOException;
|
||||
protected abstract void write(final DataOutput stream) throws IOException;
|
||||
protected abstract void read(int pSize, DataInput pStream) throws IOException;
|
||||
|
||||
public final int getSize() {
|
||||
return size;
|
||||
@@ -189,12 +189,12 @@ abstract class DIBHeader {
|
||||
);
|
||||
}
|
||||
|
||||
private static int[] readMasks(final DataInput stream, final boolean hasAlphaMask) throws IOException {
|
||||
private static int[] readMasks(final DataInput pStream, final boolean hasAlphaMask) throws IOException {
|
||||
int maskCount = hasAlphaMask ? 4 : 3;
|
||||
int[] masks = new int[4];
|
||||
|
||||
for (int i = 0; i < maskCount; i++) {
|
||||
masks[i] = stream.readInt();
|
||||
masks[i] = pStream.readInt();
|
||||
}
|
||||
|
||||
return masks;
|
||||
@@ -205,30 +205,24 @@ abstract class DIBHeader {
|
||||
// TODO: Get rid of code duplication below...
|
||||
|
||||
static final class BitmapCoreHeader extends DIBHeader {
|
||||
@Override
|
||||
protected void read(final int size, final DataInput stream) throws IOException {
|
||||
if (size != DIB.BITMAP_CORE_HEADER_SIZE) {
|
||||
throw new IIOException(String.format("Size: %s !=: %s", size, DIB.BITMAP_CORE_HEADER_SIZE));
|
||||
protected void read(final int pSize, final DataInput pStream) throws IOException {
|
||||
if (pSize != DIB.BITMAP_CORE_HEADER_SIZE) {
|
||||
throw new IIOException(String.format("Size: %s !=: %s", pSize, DIB.BITMAP_CORE_HEADER_SIZE));
|
||||
}
|
||||
|
||||
this.size = size;
|
||||
size = pSize;
|
||||
|
||||
// NOTE: Unlike all other headers, width and height are unsigned SHORT values (16 bit)!
|
||||
width = stream.readUnsignedShort();
|
||||
height = stream.readShort();
|
||||
width = pStream.readUnsignedShort();
|
||||
height = pStream.readShort();
|
||||
|
||||
if (height < 0) {
|
||||
height = -height;
|
||||
topDown = true;
|
||||
}
|
||||
|
||||
planes = stream.readUnsignedShort();
|
||||
bitCount = stream.readUnsignedShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void write(DataOutput stream) {
|
||||
throw new UnsupportedOperationException();
|
||||
planes = pStream.readUnsignedShort();
|
||||
bitCount = pStream.readUnsignedShort();
|
||||
}
|
||||
|
||||
public String getBMPVersion() {
|
||||
@@ -248,51 +242,45 @@ abstract class DIBHeader {
|
||||
*/
|
||||
static final class BitmapCoreHeaderV2 extends DIBHeader {
|
||||
@SuppressWarnings("unused")
|
||||
@Override
|
||||
protected void read(final int size, final DataInput stream) throws IOException {
|
||||
if (size != DIB.OS2_V2_HEADER_SIZE && size != DIB.OS2_V2_HEADER_16_SIZE) {
|
||||
throw new IIOException(String.format("Size: %s !=: %s", size, DIB.OS2_V2_HEADER_SIZE));
|
||||
protected void read(final int pSize, final DataInput pStream) throws IOException {
|
||||
if (pSize != DIB.OS2_V2_HEADER_SIZE && pSize != DIB.OS2_V2_HEADER_16_SIZE) {
|
||||
throw new IIOException(String.format("Size: %s !=: %s", pSize, DIB.OS2_V2_HEADER_SIZE));
|
||||
}
|
||||
|
||||
this.size = size;
|
||||
size = pSize;
|
||||
|
||||
width = stream.readInt();
|
||||
height = stream.readInt();
|
||||
width = pStream.readInt();
|
||||
height = pStream.readInt();
|
||||
|
||||
if (height < 0) {
|
||||
height = -height;
|
||||
topDown = true;
|
||||
}
|
||||
|
||||
planes = stream.readUnsignedShort();
|
||||
bitCount = stream.readUnsignedShort();
|
||||
planes = pStream.readUnsignedShort();
|
||||
bitCount = pStream.readUnsignedShort();
|
||||
|
||||
if (size != DIB.OS2_V2_HEADER_16_SIZE) {
|
||||
compression = stream.readInt();
|
||||
if (pSize != DIB.OS2_V2_HEADER_16_SIZE) {
|
||||
compression = pStream.readInt();
|
||||
|
||||
imageSize = stream.readInt();
|
||||
imageSize = pStream.readInt();
|
||||
|
||||
xPixelsPerMeter = stream.readInt();
|
||||
yPixelsPerMeter = stream.readInt();
|
||||
xPixelsPerMeter = pStream.readInt();
|
||||
yPixelsPerMeter = pStream.readInt();
|
||||
|
||||
colorsUsed = stream.readInt();
|
||||
colorsImportant = stream.readInt();
|
||||
colorsUsed = pStream.readInt();
|
||||
colorsImportant = pStream.readInt();
|
||||
}
|
||||
|
||||
// TODO: Use? These fields are not reflected in metadata as per now...
|
||||
int units = stream.readShort();
|
||||
int reserved = stream.readShort();
|
||||
int recording = stream.readShort(); // Recording algorithm
|
||||
int rendering = stream.readShort(); // Halftoning algorithm
|
||||
int size1 = stream.readInt(); // Reserved for halftoning use
|
||||
int size2 = stream.readInt(); // Reserved for halftoning use
|
||||
int colorEncoding = stream.readInt(); // Color model used in bitmap
|
||||
int identifier = stream.readInt(); // Reserved for application use
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void write(DataOutput stream) {
|
||||
throw new UnsupportedOperationException();
|
||||
int units = pStream.readShort();
|
||||
int reserved = pStream.readShort();
|
||||
int recording = pStream.readShort(); // Recording algorithm
|
||||
int rendering = pStream.readShort(); // Halftoning algorithm
|
||||
int size1 = pStream.readInt(); // Reserved for halftoning use
|
||||
int size2 = pStream.readInt(); // Reserved for halftoning use
|
||||
int colorEncoding = pStream.readInt(); // Color model used in bitmap
|
||||
int identifier = pStream.readInt(); // Reserved for application use
|
||||
}
|
||||
|
||||
public String getBMPVersion() {
|
||||
@@ -300,6 +288,7 @@ abstract class DIBHeader {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Represents the DIB (Device Independent Bitmap) Windows 3.0 Bitmap Information header structure.
|
||||
* This is the common format for persistent DIB structures, even if Windows
|
||||
@@ -315,46 +304,44 @@ abstract class DIBHeader {
|
||||
* @see <a href="https://forums.adobe.com/message/3272950#3272950">BITMAPV3INFOHEADER</a>.
|
||||
*/
|
||||
static final class BitmapInfoHeader extends DIBHeader {
|
||||
@Override
|
||||
protected void read(final int size, final DataInput stream) throws IOException {
|
||||
if (!(size == DIB.BITMAP_INFO_HEADER_SIZE || size == DIB.BITMAP_V2_INFO_HEADER_SIZE || size == DIB.BITMAP_V3_INFO_HEADER_SIZE)) {
|
||||
throw new IIOException(String.format("Size: %s !=: %s", size, DIB.BITMAP_INFO_HEADER_SIZE));
|
||||
protected void read(final int pSize, final DataInput pStream) throws IOException {
|
||||
if (!(pSize == DIB.BITMAP_INFO_HEADER_SIZE || pSize == DIB.BITMAP_V2_INFO_HEADER_SIZE || pSize == DIB.BITMAP_V3_INFO_HEADER_SIZE)) {
|
||||
throw new IIOException(String.format("Size: %s !=: %s", pSize, DIB.BITMAP_INFO_HEADER_SIZE));
|
||||
}
|
||||
|
||||
this.size = size;
|
||||
size = pSize;
|
||||
|
||||
width = stream.readInt();
|
||||
height = stream.readInt();
|
||||
width = pStream.readInt();
|
||||
height = pStream.readInt();
|
||||
|
||||
if (height < 0) {
|
||||
height = -height;
|
||||
topDown = true;
|
||||
}
|
||||
|
||||
planes = stream.readUnsignedShort();
|
||||
bitCount = stream.readUnsignedShort();
|
||||
compression = stream.readInt();
|
||||
planes = pStream.readUnsignedShort();
|
||||
bitCount = pStream.readUnsignedShort();
|
||||
compression = pStream.readInt();
|
||||
|
||||
imageSize = stream.readInt();
|
||||
imageSize = pStream.readInt();
|
||||
|
||||
xPixelsPerMeter = stream.readInt();
|
||||
yPixelsPerMeter = stream.readInt();
|
||||
xPixelsPerMeter = pStream.readInt();
|
||||
yPixelsPerMeter = pStream.readInt();
|
||||
|
||||
colorsUsed = stream.readInt();
|
||||
colorsImportant = stream.readInt();
|
||||
colorsUsed = pStream.readInt();
|
||||
colorsImportant = pStream.readInt();
|
||||
|
||||
// Read masks if we have V2 or V3
|
||||
// or if we have compression BITFIELDS or ALPHA_BITFIELDS
|
||||
if (this.size == DIB.BITMAP_V2_INFO_HEADER_SIZE || compression == DIB.COMPRESSION_BITFIELDS) {
|
||||
masks = readMasks(stream, false);
|
||||
if (size == DIB.BITMAP_V2_INFO_HEADER_SIZE || compression == DIB.COMPRESSION_BITFIELDS) {
|
||||
masks = readMasks(pStream, false);
|
||||
}
|
||||
else if (this.size == DIB.BITMAP_V3_INFO_HEADER_SIZE || compression == DIB.COMPRESSION_ALPHA_BITFIELDS) {
|
||||
masks = readMasks(stream, true);
|
||||
else if (size == DIB.BITMAP_V3_INFO_HEADER_SIZE || compression == DIB.COMPRESSION_ALPHA_BITFIELDS) {
|
||||
masks = readMasks(pStream, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void write(final DataOutput stream) throws IOException {
|
||||
void write(final DataOutput stream) throws IOException {
|
||||
stream.writeInt(DIB.BITMAP_INFO_HEADER_SIZE);
|
||||
|
||||
stream.writeInt(width);
|
||||
@@ -372,7 +359,7 @@ abstract class DIBHeader {
|
||||
stream.writeInt(colorsUsed);
|
||||
stream.writeInt(colorsImportant);
|
||||
|
||||
// TODO: Write masks, if COMPRESSION_BITFIELDS/COMPRESSION_ALPHA_BITFIELDS
|
||||
// TODO: Write masks, if bitfields
|
||||
}
|
||||
|
||||
public String getBMPVersion() {
|
||||
@@ -389,160 +376,105 @@ abstract class DIBHeader {
|
||||
* Represents the BITMAPV4INFOHEADER structure.
|
||||
*/
|
||||
static final class BitmapV4InfoHeader extends DIBHeader {
|
||||
@Override
|
||||
protected void read(final int size, final DataInput stream) throws IOException {
|
||||
if (size != DIB.BITMAP_V4_INFO_HEADER_SIZE) {
|
||||
throw new IIOException(String.format("Size: %s !=: %s", size, DIB.BITMAP_V4_INFO_HEADER_SIZE));
|
||||
protected void read(final int pSize, final DataInput pStream) throws IOException {
|
||||
if (pSize != DIB.BITMAP_V4_INFO_HEADER_SIZE) {
|
||||
throw new IIOException(String.format("Size: %s !=: %s", pSize, DIB.BITMAP_V4_INFO_HEADER_SIZE));
|
||||
}
|
||||
|
||||
this.size = size;
|
||||
size = pSize;
|
||||
|
||||
width = stream.readInt();
|
||||
height = stream.readInt();
|
||||
width = pStream.readInt();
|
||||
height = pStream.readInt();
|
||||
|
||||
if (height < 0) {
|
||||
height = -height;
|
||||
topDown = true;
|
||||
}
|
||||
|
||||
planes = stream.readUnsignedShort();
|
||||
bitCount = stream.readUnsignedShort();
|
||||
compression = stream.readInt();
|
||||
planes = pStream.readUnsignedShort();
|
||||
bitCount = pStream.readUnsignedShort();
|
||||
compression = pStream.readInt();
|
||||
|
||||
imageSize = stream.readInt();
|
||||
imageSize = pStream.readInt();
|
||||
|
||||
xPixelsPerMeter = stream.readInt();
|
||||
yPixelsPerMeter = stream.readInt();
|
||||
xPixelsPerMeter = pStream.readInt();
|
||||
yPixelsPerMeter = pStream.readInt();
|
||||
|
||||
colorsUsed = stream.readInt();
|
||||
colorsImportant = stream.readInt();
|
||||
colorsUsed = pStream.readInt();
|
||||
colorsImportant = pStream.readInt();
|
||||
|
||||
masks = readMasks(stream, true);
|
||||
masks = readMasks(pStream, true);
|
||||
|
||||
colorSpaceType = stream.readInt(); // Should be 0 for V4
|
||||
colorSpaceType = pStream.readInt(); // Should be 0 for V4
|
||||
cieXYZEndpoints = new double[9];
|
||||
|
||||
for (int i = 0; i < cieXYZEndpoints.length; i++) {
|
||||
cieXYZEndpoints[i] = stream.readInt(); // TODO: Hmmm...?
|
||||
cieXYZEndpoints[i] = pStream.readInt(); // TODO: Hmmm...?
|
||||
}
|
||||
|
||||
gamma = new int[3];
|
||||
|
||||
for (int i = 0; i < gamma.length; i++) {
|
||||
gamma[i] = stream.readInt();
|
||||
gamma[i] = pStream.readInt();
|
||||
}
|
||||
}
|
||||
|
||||
public String getBMPVersion() {
|
||||
return "BMP v. 4.x";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void write(DataOutput stream) throws IOException {
|
||||
stream.writeInt(DIB.BITMAP_V4_INFO_HEADER_SIZE);
|
||||
|
||||
stream.writeInt(width);
|
||||
stream.writeInt(topDown ? -height : height);
|
||||
|
||||
stream.writeShort(planes);
|
||||
stream.writeShort(bitCount);
|
||||
stream.writeInt(compression);
|
||||
|
||||
stream.writeInt(imageSize);
|
||||
|
||||
stream.writeInt(xPixelsPerMeter);
|
||||
stream.writeInt(yPixelsPerMeter);
|
||||
|
||||
stream.writeInt(colorsUsed);
|
||||
stream.writeInt(colorsImportant);
|
||||
|
||||
// Red, Green, Blue, Alpha masks
|
||||
stream.writeInt(masks[0]);
|
||||
stream.writeInt(masks[1]);
|
||||
stream.writeInt(masks[2]);
|
||||
stream.writeInt(masks[3]);
|
||||
|
||||
// color space ("sRGB" LITTLE endian)
|
||||
stream.writeInt(DIB.LCS_sRGB);
|
||||
|
||||
// 36 bytes CIE XYZ triples, unused for sRGB
|
||||
stream.writeInt(0);
|
||||
stream.writeInt(0);
|
||||
stream.writeInt(0);
|
||||
|
||||
stream.writeInt(0);
|
||||
stream.writeInt(0);
|
||||
stream.writeInt(0);
|
||||
|
||||
stream.writeInt(0);
|
||||
stream.writeInt(0);
|
||||
stream.writeInt(0);
|
||||
|
||||
// Red gamma, unused for sRGB
|
||||
// Green gamma, unused for sRGB
|
||||
// Blue gamma, unused for sRGB
|
||||
stream.writeInt(0);
|
||||
stream.writeInt(0);
|
||||
stream.writeInt(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the BITMAPV5INFOHEADER structure.
|
||||
*/
|
||||
static final class BitmapV5InfoHeader extends DIBHeader {
|
||||
protected void read(final int size, final DataInput stream) throws IOException {
|
||||
if (size != DIB.BITMAP_V5_INFO_HEADER_SIZE) {
|
||||
throw new IIOException(String.format("Size: %s !=: %s", size, DIB.BITMAP_V5_INFO_HEADER_SIZE));
|
||||
protected void read(final int pSize, final DataInput pStream) throws IOException {
|
||||
if (pSize != DIB.BITMAP_V5_INFO_HEADER_SIZE) {
|
||||
throw new IIOException(String.format("Size: %s !=: %s", pSize, DIB.BITMAP_V5_INFO_HEADER_SIZE));
|
||||
}
|
||||
|
||||
this.size = size;
|
||||
size = pSize;
|
||||
|
||||
width = stream.readInt();
|
||||
height = stream.readInt();
|
||||
width = pStream.readInt();
|
||||
height = pStream.readInt();
|
||||
|
||||
if (height < 0) {
|
||||
height = -height;
|
||||
topDown = true;
|
||||
}
|
||||
|
||||
planes = stream.readUnsignedShort();
|
||||
bitCount = stream.readUnsignedShort();
|
||||
compression = stream.readInt();
|
||||
planes = pStream.readUnsignedShort();
|
||||
bitCount = pStream.readUnsignedShort();
|
||||
compression = pStream.readInt();
|
||||
|
||||
imageSize = stream.readInt();
|
||||
imageSize = pStream.readInt();
|
||||
|
||||
xPixelsPerMeter = stream.readInt();
|
||||
yPixelsPerMeter = stream.readInt();
|
||||
xPixelsPerMeter = pStream.readInt();
|
||||
yPixelsPerMeter = pStream.readInt();
|
||||
|
||||
colorsUsed = stream.readInt();
|
||||
colorsImportant = stream.readInt();
|
||||
colorsUsed = pStream.readInt();
|
||||
colorsImportant = pStream.readInt();
|
||||
|
||||
masks = readMasks(stream, true);
|
||||
masks = readMasks(pStream, true);
|
||||
|
||||
colorSpaceType = stream.readInt();
|
||||
colorSpaceType = pStream.readInt();
|
||||
|
||||
cieXYZEndpoints = new double[9];
|
||||
|
||||
for (int i = 0; i < cieXYZEndpoints.length; i++) {
|
||||
cieXYZEndpoints[i] = stream.readInt(); // TODO: Hmmm...?
|
||||
cieXYZEndpoints[i] = pStream.readInt(); // TODO: Hmmm...?
|
||||
}
|
||||
|
||||
gamma = new int[3];
|
||||
|
||||
for (int i = 0; i < gamma.length; i++) {
|
||||
gamma[i] = stream.readInt();
|
||||
gamma[i] = pStream.readInt();
|
||||
}
|
||||
|
||||
intent = stream.readInt(); // TODO: Verify if this is same as ICC intent
|
||||
profileData = stream.readInt() & 0xffffffffL;
|
||||
profileSize = stream.readInt() & 0xffffffffL;
|
||||
stream.readInt(); // Reserved
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void write(DataOutput stream) {
|
||||
throw new UnsupportedOperationException();
|
||||
intent = pStream.readInt(); // TODO: Verify if this is same as ICC intent
|
||||
profileData = pStream.readInt() & 0xffffffffL;
|
||||
profileSize = pStream.readInt() & 0xffffffffL;
|
||||
pStream.readInt(); // Reserved
|
||||
}
|
||||
|
||||
public String getBMPVersion() {
|
||||
|
||||
+155
-152
@@ -30,23 +30,10 @@
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||
|
||||
import com.twelvemonkeys.image.ImageUtil;
|
||||
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||
import com.twelvemonkeys.imageio.stream.SubImageInputStream;
|
||||
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
||||
import com.twelvemonkeys.util.WeakWeakMap;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.color.*;
|
||||
import java.awt.event.*;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.image.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -57,6 +44,21 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import javax.swing.*;
|
||||
|
||||
import com.twelvemonkeys.image.ImageUtil;
|
||||
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||
import com.twelvemonkeys.imageio.stream.SubImageInputStream;
|
||||
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
||||
import com.twelvemonkeys.util.WeakWeakMap;
|
||||
|
||||
/**
|
||||
* ImageReader for Microsoft Windows ICO (icon) format.
|
||||
* 1, 4, 8 bit palette support with bitmask transparency, and 16, 24 and 32 bit
|
||||
@@ -79,13 +81,13 @@ abstract class DIBImageReader extends ImageReaderBase {
|
||||
private Directory directory;
|
||||
|
||||
// TODO: Review these, make sure we don't have a memory leak
|
||||
private final Map<DirectoryEntry, DIBHeader> headers = new WeakHashMap<>();
|
||||
private final Map<DirectoryEntry, BitmapDescriptor> descriptors = new WeakWeakMap<>();
|
||||
private Map<DirectoryEntry, DIBHeader> headers = new WeakHashMap<>();
|
||||
private Map<DirectoryEntry, BitmapDescriptor> descriptors = new WeakWeakMap<>();
|
||||
|
||||
private ImageReader pngImageReader;
|
||||
|
||||
protected DIBImageReader(final ImageReaderSpi provider) {
|
||||
super(provider);
|
||||
protected DIBImageReader(final ImageReaderSpi pProvider) {
|
||||
super(pProvider);
|
||||
}
|
||||
|
||||
protected void resetMembers() {
|
||||
@@ -100,8 +102,8 @@ abstract class DIBImageReader extends ImageReaderBase {
|
||||
}
|
||||
}
|
||||
|
||||
public Iterator<ImageTypeSpecifier> getImageTypes(final int imageIndex) throws IOException {
|
||||
DirectoryEntry entry = getEntry(imageIndex);
|
||||
public Iterator<ImageTypeSpecifier> getImageTypes(final int pImageIndex) throws IOException {
|
||||
DirectoryEntry entry = getEntry(pImageIndex);
|
||||
|
||||
// NOTE: Delegate to PNG reader
|
||||
if (isPNG(entry)) {
|
||||
@@ -153,39 +155,39 @@ abstract class DIBImageReader extends ImageReaderBase {
|
||||
return getDirectory().count();
|
||||
}
|
||||
|
||||
public int getWidth(final int imageIndex) throws IOException {
|
||||
return getEntry(imageIndex).getWidth();
|
||||
public int getWidth(final int pImageIndex) throws IOException {
|
||||
return getEntry(pImageIndex).getWidth();
|
||||
}
|
||||
|
||||
public int getHeight(final int imageIndex) throws IOException {
|
||||
return getEntry(imageIndex).getHeight();
|
||||
public int getHeight(final int pImageIndex) throws IOException {
|
||||
return getEntry(pImageIndex).getHeight();
|
||||
}
|
||||
|
||||
public BufferedImage read(final int imageIndex, final ImageReadParam param) throws IOException {
|
||||
checkBounds(imageIndex);
|
||||
public BufferedImage read(final int pImageIndex, final ImageReadParam pParam) throws IOException {
|
||||
checkBounds(pImageIndex);
|
||||
|
||||
processImageStarted(imageIndex);
|
||||
processImageStarted(pImageIndex);
|
||||
|
||||
DirectoryEntry entry = getEntry(imageIndex);
|
||||
DirectoryEntry entry = getEntry(pImageIndex);
|
||||
|
||||
BufferedImage destination;
|
||||
|
||||
if (isPNG(entry)) {
|
||||
// NOTE: Special case for Windows Vista, 256x256 PNG encoded images, with no DIB header...
|
||||
destination = readPNG(entry, param);
|
||||
destination = readPNG(entry, pParam);
|
||||
}
|
||||
else {
|
||||
// NOTE: If param does not have explicit destination, we'll try to create a BufferedImage later,
|
||||
// to allow for storing the cursor hotspot for CUR images
|
||||
destination = hasExplicitDestination(param) ?
|
||||
getDestination(param, getImageTypes(imageIndex), getWidth(imageIndex), getHeight(imageIndex)) : null;
|
||||
destination = hasExplicitDestination(pParam) ?
|
||||
getDestination(pParam, getImageTypes(pImageIndex), getWidth(pImageIndex), getHeight(pImageIndex)) : null;
|
||||
|
||||
BufferedImage image = readBitmap(entry);
|
||||
|
||||
// TODO: Handle AOI and subsampling inline, probably not of big importance...
|
||||
if (param != null) {
|
||||
image = fakeAOI(image, param);
|
||||
image = ImageUtil.toBuffered(fakeSubsampling(image, param));
|
||||
if (pParam != null) {
|
||||
image = fakeAOI(image, pParam);
|
||||
image = ImageUtil.toBuffered(fakeSubsampling(image, pParam));
|
||||
}
|
||||
|
||||
if (destination == null) {
|
||||
@@ -211,10 +213,10 @@ abstract class DIBImageReader extends ImageReaderBase {
|
||||
return destination;
|
||||
}
|
||||
|
||||
private boolean isPNG(final DirectoryEntry entry) throws IOException {
|
||||
private boolean isPNG(final DirectoryEntry pEntry) throws IOException {
|
||||
long magic;
|
||||
|
||||
imageInput.seek(entry.getOffset());
|
||||
imageInput.seek(pEntry.getOffset());
|
||||
imageInput.setByteOrder(ByteOrder.BIG_ENDIAN);
|
||||
|
||||
try {
|
||||
@@ -227,20 +229,22 @@ abstract class DIBImageReader extends ImageReaderBase {
|
||||
return magic == DIB.PNG_MAGIC;
|
||||
}
|
||||
|
||||
private BufferedImage readPNG(final DirectoryEntry entry, final ImageReadParam param) throws IOException {
|
||||
private BufferedImage readPNG(final DirectoryEntry pEntry, final ImageReadParam pParam) throws IOException {
|
||||
// TODO: Consider delegating listener calls
|
||||
return initPNGReader(entry).read(0, param);
|
||||
return initPNGReader(pEntry).read(0, pParam);
|
||||
}
|
||||
|
||||
private Iterator<ImageTypeSpecifier> getImageTypesPNG(final DirectoryEntry entry) throws IOException {
|
||||
return initPNGReader(entry).getImageTypes(0);
|
||||
private Iterator<ImageTypeSpecifier> getImageTypesPNG(final DirectoryEntry pEntry) throws IOException {
|
||||
return initPNGReader(pEntry).getImageTypes(0);
|
||||
}
|
||||
|
||||
private ImageReader initPNGReader(final DirectoryEntry entry) throws IOException {
|
||||
private ImageReader initPNGReader(final DirectoryEntry pEntry) throws IOException {
|
||||
ImageReader pngReader = getPNGReader();
|
||||
|
||||
imageInput.seek(entry.getOffset());
|
||||
ImageInputStream stream = new SubImageInputStream(imageInput, entry.getSize());
|
||||
imageInput.seek(pEntry.getOffset());
|
||||
// InputStream inputStream = IIOUtil.createStreamAdapter(imageInput, pEntry.getSize());
|
||||
// ImageInputStream stream = ImageIO.createImageInputStream(inputStream);
|
||||
ImageInputStream stream = new SubImageInputStream(imageInput, pEntry.getSize());
|
||||
|
||||
// NOTE: Will throw IOException on later reads if input is not PNG
|
||||
pngReader.setInput(stream);
|
||||
@@ -267,31 +271,31 @@ abstract class DIBImageReader extends ImageReaderBase {
|
||||
return pngImageReader;
|
||||
}
|
||||
|
||||
private DIBHeader getHeader(final DirectoryEntry entry) throws IOException {
|
||||
if (!headers.containsKey(entry)) {
|
||||
imageInput.seek(entry.getOffset());
|
||||
private DIBHeader getHeader(final DirectoryEntry pEntry) throws IOException {
|
||||
if (!headers.containsKey(pEntry)) {
|
||||
imageInput.seek(pEntry.getOffset());
|
||||
DIBHeader header = DIBHeader.read(imageInput);
|
||||
headers.put(entry, header);
|
||||
headers.put(pEntry, header);
|
||||
}
|
||||
|
||||
return headers.get(entry);
|
||||
return headers.get(pEntry);
|
||||
}
|
||||
|
||||
private BufferedImage readBitmap(final DirectoryEntry entry) throws IOException {
|
||||
private BufferedImage readBitmap(final DirectoryEntry pEntry) throws IOException {
|
||||
// TODO: Get rid of the caching, as the images are mutable
|
||||
BitmapDescriptor descriptor = descriptors.get(entry);
|
||||
BitmapDescriptor descriptor = descriptors.get(pEntry);
|
||||
|
||||
if (descriptor == null || !descriptors.containsKey(entry)) {
|
||||
DIBHeader header = getHeader(entry);
|
||||
if (descriptor == null || !descriptors.containsKey(pEntry)) {
|
||||
DIBHeader header = getHeader(pEntry);
|
||||
|
||||
int offset = entry.getOffset() + header.getSize();
|
||||
int offset = pEntry.getOffset() + header.getSize();
|
||||
if (offset != imageInput.getStreamPosition()) {
|
||||
imageInput.seek(offset);
|
||||
}
|
||||
|
||||
// TODO: Support this, it's already in the BMP reader, spec allows RLE4 and RLE8
|
||||
if (header.getCompression() != DIB.COMPRESSION_RGB) {
|
||||
descriptor = new BitmapUnsupported(entry, header, String.format("Unsupported compression: %d", header.getCompression()));
|
||||
descriptor = new BitmapUnsupported(pEntry, header, String.format("Unsupported compression: %d", header.getCompression()));
|
||||
}
|
||||
else {
|
||||
int bitCount = header.getBitCount();
|
||||
@@ -301,75 +305,75 @@ abstract class DIBImageReader extends ImageReaderBase {
|
||||
case 1:
|
||||
case 4:
|
||||
case 8: // TODO: Gray!
|
||||
descriptor = new BitmapIndexed(entry, header);
|
||||
descriptor = new BitmapIndexed(pEntry, header);
|
||||
readBitmapIndexed((BitmapIndexed) descriptor);
|
||||
break;
|
||||
// RGB style
|
||||
case 16:
|
||||
descriptor = new BitmapRGB(entry, header);
|
||||
descriptor = new BitmapRGB(pEntry, header);
|
||||
readBitmap16(descriptor);
|
||||
break;
|
||||
case 24:
|
||||
descriptor = new BitmapRGB(entry, header);
|
||||
descriptor = new BitmapRGB(pEntry, header);
|
||||
readBitmap24(descriptor);
|
||||
break;
|
||||
case 32:
|
||||
descriptor = new BitmapRGB(entry, header);
|
||||
descriptor = new BitmapRGB(pEntry, header);
|
||||
readBitmap32(descriptor);
|
||||
break;
|
||||
|
||||
default:
|
||||
descriptor = new BitmapUnsupported(entry, header, String.format("Unsupported bit count %d", bitCount));
|
||||
descriptor = new BitmapUnsupported(pEntry, header, String.format("Unsupported bit count %d", bitCount));
|
||||
}
|
||||
}
|
||||
|
||||
descriptors.put(entry, descriptor);
|
||||
descriptors.put(pEntry, descriptor);
|
||||
}
|
||||
|
||||
return descriptor.getImage();
|
||||
}
|
||||
|
||||
private void readBitmapIndexed(final BitmapIndexed bitmap) throws IOException {
|
||||
readColorMap(bitmap);
|
||||
private void readBitmapIndexed(final BitmapIndexed pBitmap) throws IOException {
|
||||
readColorMap(pBitmap);
|
||||
|
||||
switch (bitmap.getBitCount()) {
|
||||
switch (pBitmap.getBitCount()) {
|
||||
case 1:
|
||||
readBitmapIndexed1(bitmap, false);
|
||||
readBitmapIndexed1(pBitmap, false);
|
||||
break;
|
||||
case 4:
|
||||
readBitmapIndexed4(bitmap);
|
||||
readBitmapIndexed4(pBitmap);
|
||||
break;
|
||||
case 8:
|
||||
readBitmapIndexed8(bitmap);
|
||||
readBitmapIndexed8(pBitmap);
|
||||
break;
|
||||
}
|
||||
|
||||
BitmapMask mask = new BitmapMask(bitmap.entry, bitmap.header);
|
||||
BitmapMask mask = new BitmapMask(pBitmap.entry, pBitmap.header);
|
||||
readBitmapIndexed1(mask.bitMask, true);
|
||||
bitmap.setMask(mask);
|
||||
pBitmap.setMask(mask);
|
||||
}
|
||||
|
||||
private void readColorMap(final BitmapIndexed bitmap) throws IOException {
|
||||
int colorCount = bitmap.getColorCount();
|
||||
private void readColorMap(final BitmapIndexed pBitmap) throws IOException {
|
||||
int colorCount = pBitmap.getColorCount();
|
||||
|
||||
for (int i = 0; i < colorCount; i++) {
|
||||
// aRGB (a is "Reserved")
|
||||
bitmap.colors[i] = (imageInput.readInt() & 0xffffff) | 0xff000000;
|
||||
pBitmap.colors[i] = (imageInput.readInt() & 0xffffff) | 0xff000000;
|
||||
}
|
||||
}
|
||||
|
||||
private void readBitmapIndexed1(final BitmapIndexed bitmap, final boolean asMask) throws IOException {
|
||||
int width = adjustToPadding((bitmap.getWidth() + 7) >> 3);
|
||||
private void readBitmapIndexed1(final BitmapIndexed pBitmap, final boolean pAsMask) throws IOException {
|
||||
int width = adjustToPadding((pBitmap.getWidth() + 7) >> 3);
|
||||
byte[] row = new byte[width];
|
||||
|
||||
for (int y = 0; y < bitmap.getHeight(); y++) {
|
||||
for (int y = 0; y < pBitmap.getHeight(); y++) {
|
||||
imageInput.readFully(row, 0, width);
|
||||
int rowPos = 0;
|
||||
int xOrVal = 0x80;
|
||||
int pos = (bitmap.getHeight() - y - 1) * bitmap.getWidth();
|
||||
int pos = (pBitmap.getHeight() - y - 1) * pBitmap.getWidth();
|
||||
|
||||
for (int x = 0; x < bitmap.getWidth(); x++) {
|
||||
bitmap.bits[pos++] = ((row[rowPos] & xOrVal) / xOrVal) & 0xFF;
|
||||
for (int x = 0; x < pBitmap.getWidth(); x++) {
|
||||
pBitmap.bits[pos++] = ((row[rowPos] & xOrVal) / xOrVal) & 0xFF;
|
||||
|
||||
if (xOrVal == 1) {
|
||||
xOrVal = 0x80;
|
||||
@@ -380,29 +384,29 @@ abstract class DIBImageReader extends ImageReaderBase {
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: If we are reading the mask, we can't abort or report progress
|
||||
if (!asMask) {
|
||||
// NOTE: If we are reading the mask, we don't abort or report progress
|
||||
if (!pAsMask) {
|
||||
if (abortRequested()) {
|
||||
processReadAborted();
|
||||
break;
|
||||
}
|
||||
|
||||
processImageProgress(100 * y / (float) bitmap.getHeight());
|
||||
processImageProgress(100 * y / (float) pBitmap.getHeight());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readBitmapIndexed4(final BitmapIndexed bitmap) throws IOException {
|
||||
int width = adjustToPadding((bitmap.getWidth() + 1) >> 1);
|
||||
private void readBitmapIndexed4(final BitmapIndexed pBitmap) throws IOException {
|
||||
int width = adjustToPadding((pBitmap.getWidth() + 1) >> 1);
|
||||
byte[] row = new byte[width];
|
||||
|
||||
for (int y = 0; y < bitmap.getHeight(); y++) {
|
||||
for (int y = 0; y < pBitmap.getHeight(); y++) {
|
||||
imageInput.readFully(row, 0, width);
|
||||
int rowPos = 0;
|
||||
boolean high4 = true;
|
||||
int pos = (bitmap.getHeight() - y - 1) * bitmap.getWidth();
|
||||
int pos = (pBitmap.getHeight() - y - 1) * pBitmap.getWidth();
|
||||
|
||||
for (int x = 0; x < bitmap.getWidth(); x++) {
|
||||
for (int x = 0; x < pBitmap.getWidth(); x++) {
|
||||
int value;
|
||||
|
||||
if (high4) {
|
||||
@@ -413,7 +417,7 @@ abstract class DIBImageReader extends ImageReaderBase {
|
||||
rowPos++;
|
||||
}
|
||||
|
||||
bitmap.bits[pos++] = value & 0xFF;
|
||||
pBitmap.bits[pos++] = value & 0xFF;
|
||||
high4 = !high4;
|
||||
}
|
||||
|
||||
@@ -422,22 +426,22 @@ abstract class DIBImageReader extends ImageReaderBase {
|
||||
break;
|
||||
}
|
||||
|
||||
processImageProgress(100 * y / (float) bitmap.getHeight());
|
||||
processImageProgress(100 * y / (float) pBitmap.getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
private void readBitmapIndexed8(final BitmapIndexed bitmap) throws IOException {
|
||||
int width = adjustToPadding(bitmap.getWidth());
|
||||
private void readBitmapIndexed8(final BitmapIndexed pBitmap) throws IOException {
|
||||
int width = adjustToPadding(pBitmap.getWidth());
|
||||
|
||||
byte[] row = new byte[width];
|
||||
|
||||
for (int y = 0; y < bitmap.getHeight(); y++) {
|
||||
for (int y = 0; y < pBitmap.getHeight(); y++) {
|
||||
imageInput.readFully(row, 0, width);
|
||||
int rowPos = 0;
|
||||
int pos = (bitmap.getHeight() - y - 1) * bitmap.getWidth();
|
||||
int pos = (pBitmap.getHeight() - y - 1) * pBitmap.getWidth();
|
||||
|
||||
for (int x = 0; x < bitmap.getWidth(); x++) {
|
||||
bitmap.bits[pos++] = row[rowPos++] & 0xFF;
|
||||
for (int x = 0; x < pBitmap.getWidth(); x++) {
|
||||
pBitmap.bits[pos++] = row[rowPos++] & 0xFF;
|
||||
}
|
||||
|
||||
if (abortRequested()) {
|
||||
@@ -445,41 +449,40 @@ abstract class DIBImageReader extends ImageReaderBase {
|
||||
break;
|
||||
}
|
||||
|
||||
processImageProgress(100 * y / (float) bitmap.getHeight());
|
||||
processImageProgress(100 * y / (float) pBitmap.getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param width Bytes per scan line (i.e., 1BPP, width = 9 -> bytes = 2)
|
||||
* @param pWidth Bytes per scan line (i.e., 1BPP, width = 9 -> bytes = 1)
|
||||
* @return padded width
|
||||
*/
|
||||
private static int adjustToPadding(final int width) {
|
||||
if ((width & 0x03) != 0) {
|
||||
return (width & ~0x03) + 4;
|
||||
private static int adjustToPadding(final int pWidth) {
|
||||
if ((pWidth & 0x03) != 0) {
|
||||
return (pWidth & ~0x03) + 4;
|
||||
}
|
||||
|
||||
return width;
|
||||
return pWidth;
|
||||
}
|
||||
|
||||
private void readBitmap16(final BitmapDescriptor bitmap) throws IOException {
|
||||
short[] pixels = new short[bitmap.getWidth() * bitmap.getHeight()];
|
||||
private void readBitmap16(final BitmapDescriptor pBitmap) throws IOException {
|
||||
short[] pixels = new short[pBitmap.getWidth() * pBitmap.getHeight()];
|
||||
|
||||
// TODO: Support TYPE_USHORT_565 and the RGB 444/ARGB 4444 layouts
|
||||
// Will create TYPE_USHORT_555
|
||||
DirectColorModel cm = new DirectColorModel(16, 0x7C00, 0x03E0, 0x001F);
|
||||
DataBuffer buffer = new DataBufferUShort(pixels, pixels.length);
|
||||
WritableRaster raster = Raster.createPackedRaster(
|
||||
buffer, bitmap.getWidth(), bitmap.getHeight(), bitmap.getWidth(), cm.getMasks(), null
|
||||
buffer, pBitmap.getWidth(), pBitmap.getHeight(), pBitmap.getWidth(), cm.getMasks(), null
|
||||
);
|
||||
bitmap.image = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
|
||||
pBitmap.image = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
|
||||
|
||||
for (int y = 0; y < bitmap.getHeight(); y++) {
|
||||
int offset = (bitmap.getHeight() - y - 1) * bitmap.getWidth();
|
||||
imageInput.readFully(pixels, offset, bitmap.getWidth());
|
||||
for (int y = 0; y < pBitmap.getHeight(); y++) {
|
||||
int offset = (pBitmap.getHeight() - y - 1) * pBitmap.getWidth();
|
||||
imageInput.readFully(pixels, offset, pBitmap.getWidth());
|
||||
|
||||
|
||||
// Skip to 32 bit boundary
|
||||
if (bitmap.getWidth() % 2 != 0) {
|
||||
if (pBitmap.getWidth() % 2 != 0) {
|
||||
imageInput.readShort();
|
||||
}
|
||||
|
||||
@@ -488,14 +491,14 @@ abstract class DIBImageReader extends ImageReaderBase {
|
||||
break;
|
||||
}
|
||||
|
||||
processImageProgress(100 * y / (float) bitmap.getHeight());
|
||||
processImageProgress(100 * y / (float) pBitmap.getHeight());
|
||||
}
|
||||
|
||||
// TODO: Might be mask!?
|
||||
}
|
||||
|
||||
private void readBitmap24(final BitmapDescriptor bitmap) throws IOException {
|
||||
byte[] pixels = new byte[bitmap.getWidth() * bitmap.getHeight() * 3];
|
||||
private void readBitmap24(final BitmapDescriptor pBitmap) throws IOException {
|
||||
byte[] pixels = new byte[pBitmap.getWidth() * pBitmap.getHeight() * 3];
|
||||
|
||||
// Create TYPE_3BYTE_BGR
|
||||
DataBuffer buffer = new DataBufferByte(pixels, pixels.length);
|
||||
@@ -506,17 +509,17 @@ abstract class DIBImageReader extends ImageReaderBase {
|
||||
cs, nBits, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE
|
||||
);
|
||||
|
||||
int scanlineStride = bitmap.getWidth() * 3;
|
||||
int scanlineStride = pBitmap.getWidth() * 3;
|
||||
// BMP rows are padded to 4 byte boundary
|
||||
int rowSizeBytes = ((8 * scanlineStride + 31) / 32) * 4;
|
||||
|
||||
WritableRaster raster = Raster.createInterleavedRaster(
|
||||
buffer, bitmap.getWidth(), bitmap.getHeight(), scanlineStride, 3, bOffs, null
|
||||
buffer, pBitmap.getWidth(), pBitmap.getHeight(), scanlineStride, 3, bOffs, null
|
||||
);
|
||||
bitmap.image = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
|
||||
pBitmap.image = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
|
||||
|
||||
for (int y = 0; y < bitmap.getHeight(); y++) {
|
||||
int offset = (bitmap.getHeight() - y - 1) * scanlineStride;
|
||||
for (int y = 0; y < pBitmap.getHeight(); y++) {
|
||||
int offset = (pBitmap.getHeight() - y - 1) * scanlineStride;
|
||||
imageInput.readFully(pixels, offset, scanlineStride);
|
||||
imageInput.skipBytes(rowSizeBytes - scanlineStride);
|
||||
|
||||
@@ -525,38 +528,38 @@ abstract class DIBImageReader extends ImageReaderBase {
|
||||
break;
|
||||
}
|
||||
|
||||
processImageProgress(100 * y / (float) bitmap.getHeight());
|
||||
processImageProgress(100 * y / (float) pBitmap.getHeight());
|
||||
}
|
||||
|
||||
// 24 bit icons usually have a bit mask
|
||||
if (bitmap.hasMask()) {
|
||||
BitmapMask mask = new BitmapMask(bitmap.entry, bitmap.header);
|
||||
if (pBitmap.hasMask()) {
|
||||
BitmapMask mask = new BitmapMask(pBitmap.entry, pBitmap.header);
|
||||
readBitmapIndexed1(mask.bitMask, true);
|
||||
|
||||
bitmap.setMask(mask);
|
||||
pBitmap.setMask(mask);
|
||||
}
|
||||
}
|
||||
|
||||
private void readBitmap32(final BitmapDescriptor bitmap) throws IOException {
|
||||
int[] pixels = new int[bitmap.getWidth() * bitmap.getHeight()];
|
||||
private void readBitmap32(final BitmapDescriptor pBitmap) throws IOException {
|
||||
int[] pixels = new int[pBitmap.getWidth() * pBitmap.getHeight()];
|
||||
|
||||
// Will create TYPE_INT_ARGB
|
||||
DirectColorModel cm = (DirectColorModel) ColorModel.getRGBdefault();
|
||||
DataBuffer buffer = new DataBufferInt(pixels, pixels.length);
|
||||
WritableRaster raster = Raster.createPackedRaster(
|
||||
buffer, bitmap.getWidth(), bitmap.getHeight(), bitmap.getWidth(), cm.getMasks(), null
|
||||
buffer, pBitmap.getWidth(), pBitmap.getHeight(), pBitmap.getWidth(), cm.getMasks(), null
|
||||
);
|
||||
bitmap.image = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
|
||||
pBitmap.image = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
|
||||
|
||||
for (int y = 0; y < bitmap.getHeight(); y++) {
|
||||
int offset = (bitmap.getHeight() - y - 1) * bitmap.getWidth();
|
||||
imageInput.readFully(pixels, offset, bitmap.getWidth());
|
||||
for (int y = 0; y < pBitmap.getHeight(); y++) {
|
||||
int offset = (pBitmap.getHeight() - y - 1) * pBitmap.getWidth();
|
||||
imageInput.readFully(pixels, offset, pBitmap.getWidth());
|
||||
|
||||
if (abortRequested()) {
|
||||
processReadAborted();
|
||||
break;
|
||||
}
|
||||
processImageProgress(100 * y / (float) bitmap.getHeight());
|
||||
processImageProgress(100 * y / (float) pBitmap.getHeight());
|
||||
}
|
||||
|
||||
// There might be a mask here as well, but we'll ignore it,
|
||||
@@ -587,18 +590,18 @@ abstract class DIBImageReader extends ImageReaderBase {
|
||||
directory = Directory.read(type, imageCount, imageInput);
|
||||
}
|
||||
|
||||
final DirectoryEntry getEntry(final int imageIndex) throws IOException {
|
||||
final DirectoryEntry getEntry(final int pImageIndex) throws IOException {
|
||||
Directory directory = getDirectory();
|
||||
if (imageIndex < 0 || imageIndex >= directory.count()) {
|
||||
throw new IndexOutOfBoundsException(String.format("Index: %d, ImageCount: %d", imageIndex, directory.count()));
|
||||
if (pImageIndex < 0 || pImageIndex >= directory.count()) {
|
||||
throw new IndexOutOfBoundsException(String.format("Index: %d, ImageCount: %d", pImageIndex, directory.count()));
|
||||
}
|
||||
|
||||
return directory.getEntry(imageIndex);
|
||||
return directory.getEntry(pImageIndex);
|
||||
}
|
||||
|
||||
/// Test code below, ignore.. :-)
|
||||
public static void main(final String[] args) throws IOException {
|
||||
if (args.length == 0) {
|
||||
public static void main(final String[] pArgs) throws IOException {
|
||||
if (pArgs.length == 0) {
|
||||
System.err.println("Please specify the icon file name");
|
||||
System.exit(1);
|
||||
}
|
||||
@@ -610,7 +613,7 @@ abstract class DIBImageReader extends ImageReaderBase {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
String title = new File(args[0]).getName();
|
||||
String title = new File(pArgs[0]).getName();
|
||||
JFrame frame = createWindow(title);
|
||||
JPanel root = new JPanel(new FlowLayout());
|
||||
JScrollPane scroll =
|
||||
@@ -626,7 +629,7 @@ abstract class DIBImageReader extends ImageReaderBase {
|
||||
|
||||
ImageReader reader = readers.next();
|
||||
|
||||
for (String arg : args) {
|
||||
for (String arg : pArgs) {
|
||||
JPanel panel = new JPanel(null);
|
||||
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
|
||||
readImagesInFile(arg, reader, panel);
|
||||
@@ -637,28 +640,28 @@ abstract class DIBImageReader extends ImageReaderBase {
|
||||
frame.setVisible(true);
|
||||
}
|
||||
|
||||
private static void readImagesInFile(String fileName, ImageReader reader, final Container container) throws IOException {
|
||||
File file = new File(fileName);
|
||||
private static void readImagesInFile(String pFileName, ImageReader pReader, final Container pContainer) throws IOException {
|
||||
File file = new File(pFileName);
|
||||
if (!file.isFile()) {
|
||||
System.err.println(fileName + " not found, or is no file");
|
||||
System.err.println(pFileName + " not found, or is no file");
|
||||
}
|
||||
|
||||
reader.setInput(ImageIO.createImageInputStream(file));
|
||||
int imageCount = reader.getNumImages(true);
|
||||
pReader.setInput(ImageIO.createImageInputStream(file));
|
||||
int imageCount = pReader.getNumImages(true);
|
||||
for (int i = 0; i < imageCount; i++) {
|
||||
try {
|
||||
addImage(container, reader, i);
|
||||
addImage(pContainer, pReader, i);
|
||||
}
|
||||
catch (Exception e) {
|
||||
System.err.println("FileName: " + fileName);
|
||||
System.err.println("FileName: " + pFileName);
|
||||
System.err.println("Icon: " + i);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static JFrame createWindow(final String title) {
|
||||
JFrame frame = new JFrame(title);
|
||||
private static JFrame createWindow(final String pTitle) {
|
||||
JFrame frame = new JFrame(pTitle);
|
||||
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||
frame.addWindowListener(new WindowAdapter() {
|
||||
public void windowClosed(WindowEvent e) {
|
||||
@@ -668,15 +671,15 @@ abstract class DIBImageReader extends ImageReaderBase {
|
||||
return frame;
|
||||
}
|
||||
|
||||
private static void addImage(final Container parent, final ImageReader reader, final int imageNo) throws IOException {
|
||||
private static void addImage(final Container pParent, final ImageReader pReader, final int pImageNo) throws IOException {
|
||||
final JButton button = new JButton();
|
||||
|
||||
BufferedImage image = reader.read(imageNo);
|
||||
BufferedImage image = pReader.read(pImageNo);
|
||||
button.setIcon(new ImageIcon(image) {
|
||||
TexturePaint texture;
|
||||
|
||||
private void createTexture(final GraphicsConfiguration graphicsConfiguration) {
|
||||
BufferedImage pattern = graphicsConfiguration.createCompatibleImage(20, 20);
|
||||
private void createTexture(final GraphicsConfiguration pGraphicsConfiguration) {
|
||||
BufferedImage pattern = pGraphicsConfiguration.createCompatibleImage(20, 20);
|
||||
Graphics2D g = pattern.createGraphics();
|
||||
try {
|
||||
g.setColor(Color.LIGHT_GRAY);
|
||||
@@ -711,6 +714,6 @@ abstract class DIBImageReader extends ImageReaderBase {
|
||||
String.valueOf(((IndexColorModel) image.getColorModel()).getMapSize()) :
|
||||
"TrueColor"));
|
||||
|
||||
parent.add(button);
|
||||
pParent.add(button);
|
||||
}
|
||||
}
|
||||
|
||||
+9
-10
@@ -44,25 +44,24 @@ import java.util.List;
|
||||
class Directory {
|
||||
private final List<DirectoryEntry> entries;
|
||||
|
||||
private Directory(int imageCount) {
|
||||
entries = Arrays.asList(new DirectoryEntry[imageCount]);
|
||||
private Directory(int pImageCount) {
|
||||
entries = Arrays.asList(new DirectoryEntry[pImageCount]);
|
||||
}
|
||||
|
||||
public static Directory read(final int type, final int imageCount, final DataInput stream) throws IOException {
|
||||
Directory directory = new Directory(imageCount);
|
||||
directory.readEntries(type, stream);
|
||||
|
||||
public static Directory read(final int pType, final int pImageCount, final DataInput pStream) throws IOException {
|
||||
Directory directory = new Directory(pImageCount);
|
||||
directory.readEntries(pType, pStream);
|
||||
return directory;
|
||||
}
|
||||
|
||||
private void readEntries(final int type, final DataInput stream) throws IOException {
|
||||
private void readEntries(final int pType, final DataInput pStream) throws IOException {
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
entries.set(i, DirectoryEntry.read(type, stream));
|
||||
entries.set(i, DirectoryEntry.read(pType, pStream));
|
||||
}
|
||||
}
|
||||
|
||||
public DirectoryEntry getEntry(final int entryIndex) {
|
||||
return entries.get(entryIndex);
|
||||
public DirectoryEntry getEntry(final int pEntryIndex) {
|
||||
return entries.get(pEntryIndex);
|
||||
}
|
||||
|
||||
public int count() {
|
||||
|
||||
+24
-19
@@ -32,7 +32,8 @@ package com.twelvemonkeys.imageio.plugins.bmp;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import java.awt.*;
|
||||
import java.awt.image.*;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.IndexColorModel;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
@@ -57,43 +58,47 @@ abstract class DirectoryEntry {
|
||||
DirectoryEntry() {
|
||||
}
|
||||
|
||||
public static DirectoryEntry read(final int type, final DataInput stream) throws IOException {
|
||||
DirectoryEntry entry = createEntry(type);
|
||||
entry.read(stream);
|
||||
|
||||
public static DirectoryEntry read(final int pType, final DataInput pStream) throws IOException {
|
||||
DirectoryEntry entry = createEntry(pType);
|
||||
entry.read(pStream);
|
||||
return entry;
|
||||
}
|
||||
|
||||
private static DirectoryEntry createEntry(int type) throws IIOException {
|
||||
switch (type) {
|
||||
private static DirectoryEntry createEntry(int pType) throws IIOException {
|
||||
switch (pType) {
|
||||
case DIB.TYPE_ICO:
|
||||
return new ICOEntry();
|
||||
case DIB.TYPE_CUR:
|
||||
return new CUREntry();
|
||||
default:
|
||||
throw new IIOException(String.format("Unknown DIB type: %s, expected: %s (ICO) or %s (CUR)", type, DIB.TYPE_ICO, DIB.TYPE_CUR));
|
||||
throw new IIOException(
|
||||
String.format(
|
||||
"Unknown DIB type: %s, expected: %s (ICO) or %s (CUR)",
|
||||
pType, DIB.TYPE_ICO, DIB.TYPE_CUR
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected void read(final DataInput stream) throws IOException {
|
||||
protected void read(final DataInput pStream) throws IOException {
|
||||
// Width/height = 0, means 256
|
||||
int w = stream.readUnsignedByte();
|
||||
int w = pStream.readUnsignedByte();
|
||||
width = w == 0 ? 256 : w;
|
||||
int h = stream.readUnsignedByte();
|
||||
int h = pStream.readUnsignedByte();
|
||||
height = h == 0 ? 256 : h;
|
||||
|
||||
// Color count = 0, means 256 or more colors
|
||||
colorCount = stream.readUnsignedByte();
|
||||
colorCount = pStream.readUnsignedByte();
|
||||
|
||||
// Ignore. Should be 0, but .NET (System.Drawing.Icon.Save) sets this value to 255, according to Wikipedia
|
||||
stream.readUnsignedByte();
|
||||
pStream.readUnsignedByte();
|
||||
|
||||
planes = stream.readUnsignedShort(); // Should be 0 or 1 for ICO, x hotspot for CUR
|
||||
bitCount = stream.readUnsignedShort(); // bit count for ICO, y hotspot for CUR
|
||||
planes = pStream.readUnsignedShort(); // Should be 0 or 1 for ICO, x hotspot for CUR
|
||||
bitCount = pStream.readUnsignedShort(); // bit count for ICO, y hotspot for CUR
|
||||
|
||||
// Size of bitmap in bytes
|
||||
size = stream.readInt();
|
||||
offset = stream.readInt();
|
||||
size = pStream.readInt();
|
||||
offset = pStream.readInt();
|
||||
}
|
||||
|
||||
void write(final DataOutput output) throws IOException {
|
||||
@@ -152,8 +157,8 @@ abstract class DirectoryEntry {
|
||||
private int yHotspot;
|
||||
|
||||
@Override
|
||||
protected void read(final DataInput stream) throws IOException {
|
||||
super.read(stream);
|
||||
protected void read(final DataInput pStream) throws IOException {
|
||||
super.read(pStream);
|
||||
|
||||
// NOTE: This is a hack...
|
||||
xHotspot = planes;
|
||||
|
||||
+2
-2
@@ -46,7 +46,7 @@ public final class ICOImageReader extends DIBImageReader {
|
||||
super(new ICOImageReaderSpi());
|
||||
}
|
||||
|
||||
ICOImageReader(final ImageReaderSpi provider) {
|
||||
super(provider);
|
||||
protected ICOImageReader(final ImageReaderSpi pProvider) {
|
||||
super(pProvider);
|
||||
}
|
||||
}
|
||||
|
||||
+11
-10
@@ -32,6 +32,7 @@ package com.twelvemonkeys.imageio.plugins.bmp;
|
||||
|
||||
import com.twelvemonkeys.imageio.spi.ImageReaderSpiBase;
|
||||
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
@@ -48,32 +49,32 @@ public final class ICOImageReaderSpi extends ImageReaderSpiBase {
|
||||
super(new ICOProviderInfo());
|
||||
}
|
||||
|
||||
public boolean canDecodeInput(final Object source) throws IOException {
|
||||
return source instanceof ImageInputStream && canDecode((ImageInputStream) source, DIB.TYPE_ICO);
|
||||
public boolean canDecodeInput(final Object pSource) throws IOException {
|
||||
return pSource instanceof ImageInputStream && canDecode((ImageInputStream) pSource, DIB.TYPE_ICO);
|
||||
}
|
||||
|
||||
static boolean canDecode(final ImageInputStream input, final int type) throws IOException {
|
||||
static boolean canDecode(final ImageInputStream pInput, final int pType) throws IOException {
|
||||
byte[] signature = new byte[4];
|
||||
|
||||
try {
|
||||
input.mark();
|
||||
input.readFully(signature);
|
||||
pInput.mark();
|
||||
pInput.readFully(signature);
|
||||
|
||||
int count = input.readByte() + (input.readByte() << 8);
|
||||
int count = pInput.readByte() + (pInput.readByte() << 8);
|
||||
|
||||
return (signature[0] == 0x0 && signature[1] == 0x0 && signature[2] == type
|
||||
return (signature[0] == 0x0 && signature[1] == 0x0 && signature[2] == pType
|
||||
&& signature[3] == 0x0 && count > 0);
|
||||
}
|
||||
finally {
|
||||
input.reset();
|
||||
pInput.reset();
|
||||
}
|
||||
}
|
||||
|
||||
public ICOImageReader createReaderInstance(final Object extension) {
|
||||
public ImageReader createReaderInstance(final Object pExtension) throws IOException {
|
||||
return new ICOImageReader(this);
|
||||
}
|
||||
|
||||
public String getDescription(final Locale locale) {
|
||||
public String getDescription(final Locale pLocale) {
|
||||
return "Windows Icon Format (ICO) Reader";
|
||||
}
|
||||
}
|
||||
|
||||
+6
-10
@@ -33,19 +33,15 @@ package com.twelvemonkeys.imageio.plugins.bmp;
|
||||
import com.twelvemonkeys.imageio.stream.SubImageOutputStream;
|
||||
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.IIOImage;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.ImageWriteParam;
|
||||
import javax.imageio.ImageWriter;
|
||||
import javax.imageio.*;
|
||||
import javax.imageio.event.IIOWriteWarningListener;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.spi.ImageWriterSpi;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import javax.imageio.stream.ImageOutputStream;
|
||||
import java.awt.image.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
@@ -68,7 +64,7 @@ public final class ICOImageWriter extends DIBImageWriter {
|
||||
|
||||
private ImageWriter pngDelegate;
|
||||
|
||||
ICOImageWriter(final ImageWriterSpi provider) {
|
||||
protected ICOImageWriter(final ImageWriterSpi provider) {
|
||||
super(provider);
|
||||
}
|
||||
|
||||
@@ -128,7 +124,7 @@ public final class ICOImageWriter extends DIBImageWriter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endWriteSequence() {
|
||||
public void endWriteSequence() throws IOException {
|
||||
assertOutput();
|
||||
|
||||
if (sequenceIndex < 0) {
|
||||
|
||||
+29
-26
@@ -30,14 +30,24 @@
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.bmp;
|
||||
|
||||
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
||||
import com.twelvemonkeys.xml.XMLSerializer;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assume.assumeNoException;
|
||||
import static org.mockito.ArgumentMatchers.anyFloat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InOrder;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.ImageIO;
|
||||
@@ -47,25 +57,16 @@ import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.event.IIOReadProgressListener;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.metadata.IIOMetadataNode;
|
||||
import javax.imageio.spi.IIORegistry;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import java.awt.*;
|
||||
import java.awt.image.*;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assume.assumeNoException;
|
||||
import static org.mockito.ArgumentMatchers.anyFloat;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.inOrder;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.mockito.InOrder;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
||||
import com.twelvemonkeys.xml.XMLSerializer;
|
||||
|
||||
/**
|
||||
* BMPImageReaderTest
|
||||
@@ -325,8 +326,10 @@ public class BMPImageReaderTest extends ImageReaderAbstractTest<BMPImageReader>
|
||||
public void testMetadataEqualsJRE() throws IOException {
|
||||
ImageReader jreReader;
|
||||
try {
|
||||
ImageReaderSpi provider = (ImageReaderSpi) IIORegistry.getDefaultInstance().getServiceProviderByClass(Class.forName("com.sun.imageio.plugins.bmp.BMPImageReaderSpi"));
|
||||
jreReader = provider.createReaderInstance();
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<ImageReader> jreReaderClass = (Class<ImageReader>) Class.forName("com.sun.imageio.plugins.bmp.BMPImageReader");
|
||||
Constructor<ImageReader> constructor = jreReaderClass.getConstructor(ImageReaderSpi.class);
|
||||
jreReader = constructor.newInstance(new Object[] {null});
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.12.0</version>
|
||||
<version>3.9.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>imageio-clippath</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: Photoshop Path Support</name>
|
||||
@@ -32,13 +32,4 @@
|
||||
<artifactId>imageio-metadata</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
@@ -42,7 +42,6 @@ import com.twelvemonkeys.imageio.metadata.tiff.TIFF;
|
||||
import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader;
|
||||
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
||||
import com.twelvemonkeys.imageio.stream.SubImageInputStream;
|
||||
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
||||
|
||||
import javax.imageio.*;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
@@ -308,7 +307,7 @@ public final class Paths {
|
||||
throw new IllegalArgumentException("output == null!");
|
||||
}
|
||||
|
||||
ImageTypeSpecifier type = ImageTypeSpecifiers.createFromRenderedImage(image);
|
||||
ImageTypeSpecifier type = ImageTypeSpecifier.createFromRenderedImage(image);
|
||||
Iterator<ImageWriter> writers = ImageIO.getImageWriters(type, formatName);
|
||||
|
||||
if (writers.hasNext()) {
|
||||
|
||||
@@ -4,13 +4,10 @@
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.12.0</version>
|
||||
<version>3.9.5-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>imageio-core</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: Core</name>
|
||||
<description>
|
||||
TwelveMonkeys ImageIO core support classes.
|
||||
</description>
|
||||
|
||||
<properties>
|
||||
<project.jpms.module.name>com.twelvemonkeys.imageio.core</project.jpms.module.name>
|
||||
@@ -31,20 +28,4 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Provide-Capability>
|
||||
osgi.serviceloader;
|
||||
osgi.serviceloader=javax.imageio.spi.ImageInputStreamSpi
|
||||
</Provide-Capability>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
@@ -188,7 +188,7 @@ public final class ColorSpaces {
|
||||
// Will throw IllegalArgumentException or CMMException if the profile is bad
|
||||
cs.fromRGB(new float[] {0.999f, 0.5f, 0.001f});
|
||||
|
||||
// This breaks *sometimes* after validation of bad profiles,
|
||||
// This breaks *some times* after validation of bad profiles,
|
||||
// we'll let it blow up early in this case
|
||||
cs.getProfile().getData();
|
||||
}
|
||||
|
||||
+2
-2
@@ -37,14 +37,14 @@ import java.io.IOException;
|
||||
import static com.twelvemonkeys.lang.Validate.notNull;
|
||||
|
||||
/**
|
||||
* ImageOutputStream that writes through a delegate, but keeps local position and bit offset.
|
||||
* ImageInputStream that writes through a delegate, but keeps local position and bit offset.
|
||||
* Note: Flushing or closing this stream will *not* have an effect on the delegate.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: harald.kuhr$
|
||||
* @version $Id: SubImageOutputStream.java,v 1.0 30/03/15 harald.kuhr Exp$
|
||||
*/
|
||||
public final class SubImageOutputStream extends ImageOutputStreamImpl {
|
||||
public class SubImageOutputStream extends ImageOutputStreamImpl {
|
||||
private final ImageOutputStream stream;
|
||||
private final long startPos;
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ import javax.imageio.spi.ServiceRegistry;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import javax.imageio.stream.ImageOutputStream;
|
||||
import java.awt.*;
|
||||
import java.awt.image.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.InputStream;
|
||||
@@ -232,10 +232,6 @@ public final class IIOUtil {
|
||||
int samplesPerPixel, int bitsPerSample, int samplePeriod) {
|
||||
// Period == 1 is a no-op...
|
||||
if (samplePeriod == 1) {
|
||||
if (srcRow != destRow) {
|
||||
System.arraycopy(srcRow, srcPos, destRow, destPos, srcWidth);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -279,10 +275,6 @@ public final class IIOUtil {
|
||||
int samplesPerPixel, int bitsPerSample, int samplePeriod) {
|
||||
// Period == 1 is a no-op...
|
||||
if (samplePeriod == 1) {
|
||||
if (srcRow != destRow) {
|
||||
System.arraycopy(srcRow, srcPos, destRow, destPos, srcWidth);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -291,7 +283,7 @@ public final class IIOUtil {
|
||||
"bitsPerSample must be > 0 and <= 16 and a power of 2");
|
||||
Validate.isTrue(samplesPerPixel > 0, "samplesPerPixel must be > 0");
|
||||
Validate.isTrue(samplesPerPixel * bitsPerSample <= 16 || samplesPerPixel * bitsPerSample % 16 == 0,
|
||||
"samplesPerPixel * bitsPerSample must be < 16 or a multiple of 16");
|
||||
"samplesPerPixel * bitsPerSample must be < 16 or a multiple of 16 ");
|
||||
|
||||
int pixelStride = bitsPerSample * samplesPerPixel / 16;
|
||||
for (int x = 0; x < srcWidth * pixelStride; x += samplePeriod * pixelStride) {
|
||||
@@ -305,10 +297,6 @@ public final class IIOUtil {
|
||||
int samplesPerPixel, int bitsPerSample, int samplePeriod) {
|
||||
// Period == 1 is a no-op...
|
||||
if (samplePeriod == 1) {
|
||||
if (srcRow != destRow) {
|
||||
System.arraycopy(srcRow, srcPos, destRow, destPos, srcWidth);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -317,7 +305,7 @@ public final class IIOUtil {
|
||||
"bitsPerSample must be > 0 and <= 32 and a power of 2");
|
||||
Validate.isTrue(samplesPerPixel > 0, "samplesPerPixel must be > 0");
|
||||
Validate.isTrue(samplesPerPixel * bitsPerSample <= 32 || samplesPerPixel * bitsPerSample % 32 == 0,
|
||||
"samplesPerPixel * bitsPerSample must be < 32 or a multiple of 32");
|
||||
"samplesPerPixel * bitsPerSample must be < 32 or a multiple of 32 ");
|
||||
|
||||
int pixelStride = bitsPerSample * samplesPerPixel / 32;
|
||||
for (int x = 0; x < srcWidth * pixelStride; x += samplePeriod * pixelStride) {
|
||||
@@ -334,7 +322,7 @@ public final class IIOUtil {
|
||||
"bitsPerSample must be > 0 and <= 32 and a power of 2");
|
||||
Validate.isTrue(samplesPerPixel > 0, "samplesPerPixel must be > 0");
|
||||
Validate.isTrue(samplesPerPixel * bitsPerSample <= 32 || samplesPerPixel * bitsPerSample % 32 == 0,
|
||||
"samplesPerPixel * bitsPerSample must be < 32 or a multiple of 32");
|
||||
"samplesPerPixel * bitsPerSample must be < 32 or a multiple of 32 ");
|
||||
|
||||
int pixelStride = bitsPerSample * samplesPerPixel / 32;
|
||||
for (int x = 0; x < srcWidth * pixelStride; x += samplePeriod * pixelStride) {
|
||||
@@ -342,21 +330,4 @@ public final class IIOUtil {
|
||||
System.arraycopy(srcRow, srcPos + x, destRow, destPos + x / samplePeriod, pixelStride);
|
||||
}
|
||||
}
|
||||
|
||||
public static void subsampleRow(double[] srcRow, int srcPos, int srcWidth,
|
||||
double[] destRow, int destPos,
|
||||
int samplesPerPixel, int bitsPerSample, int samplePeriod) {
|
||||
Validate.isTrue(samplePeriod > 1, "samplePeriod must be > 1"); // Period == 1 could be a no-op...
|
||||
Validate.isTrue(bitsPerSample > 0 && bitsPerSample <= 64 && (bitsPerSample == 1 || bitsPerSample % 2 == 0),
|
||||
"bitsPerSample must be > 0 and <= 64 and a power of 2");
|
||||
Validate.isTrue(samplesPerPixel > 0, "samplesPerPixel must be > 0");
|
||||
Validate.isTrue(samplesPerPixel * bitsPerSample <= 64 || samplesPerPixel * bitsPerSample % 64 == 0,
|
||||
"samplesPerPixel * bitsPerSample must be < 64 or a multiple of 64");
|
||||
|
||||
int pixelStride = bitsPerSample * samplesPerPixel / 64;
|
||||
for (int x = 0; x < srcWidth * pixelStride; x += samplePeriod * pixelStride) {
|
||||
// System.arraycopy should be intrinsic, but consider using direct array access for pixelStride == 1
|
||||
System.arraycopy(srcRow, srcPos + x, destRow, destPos + x / samplePeriod, pixelStride);
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-11
@@ -257,18 +257,18 @@ public final class ImageTypeSpecifiers {
|
||||
return createFromIndexColorModel(new IndexColorModel(bits, colors.length, colors, 0, hasAlpha, transIndex, dataType));
|
||||
}
|
||||
|
||||
public static ImageTypeSpecifier createFromIndexColorModel(final IndexColorModel colorModel) {
|
||||
return new IndexedImageTypeSpecifier(colorModel);
|
||||
public static ImageTypeSpecifier createFromIndexColorModel(final IndexColorModel pColorModel) {
|
||||
return new IndexedImageTypeSpecifier(pColorModel);
|
||||
}
|
||||
|
||||
public static ImageTypeSpecifier createDiscreteAlphaIndexedFromIndexColorModel(final IndexColorModel colorModel) {
|
||||
ColorModel discreteAlphaIndexColorModel = new DiscreteAlphaIndexColorModel(colorModel);
|
||||
return new ImageTypeSpecifier(discreteAlphaIndexColorModel, discreteAlphaIndexColorModel.createCompatibleSampleModel(1, 1));
|
||||
public static ImageTypeSpecifier createDiscreteAlphaIndexedFromIndexColorModel(final IndexColorModel pColorModel) {
|
||||
ColorModel colorModel = new DiscreteAlphaIndexColorModel(pColorModel);
|
||||
return new ImageTypeSpecifier(colorModel, colorModel.createCompatibleSampleModel(1, 1));
|
||||
}
|
||||
|
||||
public static ImageTypeSpecifier createDiscreteExtraSamplesIndexedFromIndexColorModel(final IndexColorModel colorModel, int extraSamples, boolean hasAlpha) {
|
||||
ColorModel discreteAlphaIndexColorModel = new DiscreteAlphaIndexColorModel(colorModel, extraSamples, hasAlpha);
|
||||
return new ImageTypeSpecifier(discreteAlphaIndexColorModel, discreteAlphaIndexColorModel.createCompatibleSampleModel(1, 1));
|
||||
public static ImageTypeSpecifier createDiscreteExtraSamplesIndexedFromIndexColorModel(final IndexColorModel pColorModel, int extraSamples, boolean hasAlpha) {
|
||||
ColorModel colorModel = new DiscreteAlphaIndexColorModel(pColorModel, extraSamples, hasAlpha);
|
||||
return new ImageTypeSpecifier(colorModel, colorModel.createCompatibleSampleModel(1, 1));
|
||||
}
|
||||
|
||||
public static ImageTypeSpecifier createFromRenderedImage(RenderedImage image) {
|
||||
@@ -279,9 +279,7 @@ public final class ImageTypeSpecifiers {
|
||||
if (image instanceof BufferedImage) {
|
||||
int bufferedImageType = ((BufferedImage) image).getType();
|
||||
|
||||
if (bufferedImageType != BufferedImage.TYPE_CUSTOM &&
|
||||
// Need to retain the actual palette in the color model for IndexColorModel
|
||||
bufferedImageType != BufferedImage.TYPE_BYTE_BINARY && bufferedImageType != BufferedImage.TYPE_BYTE_INDEXED) {
|
||||
if (bufferedImageType != BufferedImage.TYPE_CUSTOM) {
|
||||
return createFromBufferedImageType(bufferedImageType);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -52,12 +52,12 @@ final class IndexedImageTypeSpecifier extends ImageTypeSpecifier {
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage createBufferedImage(final int width, final int height) {
|
||||
public final BufferedImage createBufferedImage(final int pWidth, final int pHeight) {
|
||||
try {
|
||||
// This is a fix for the super-method, that first creates a sample model, and then
|
||||
// creates a raster from it, using Raster.createWritableRaster. The problem with
|
||||
// that approach, is that it always creates a TYPE_CUSTOM BufferedImage for indexed images.
|
||||
WritableRaster raster = colorModel.createCompatibleWritableRaster(width, height);
|
||||
WritableRaster raster = colorModel.createCompatibleWritableRaster(pWidth, pHeight);
|
||||
return new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);
|
||||
}
|
||||
catch (NegativeArraySizeException e) {
|
||||
|
||||
+1
-2
@@ -17,7 +17,6 @@ import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
@@ -171,7 +170,7 @@ public class StandardImageMetadataSupportTest {
|
||||
|
||||
@Test
|
||||
public void withTextValuesMap() {
|
||||
Map<String, String> entries = new LinkedHashMap<>();
|
||||
Map<String, String> entries = new HashMap<>();
|
||||
entries.put("foo", "bar");
|
||||
entries.put("bar", "xyzzy");
|
||||
|
||||
|
||||
@@ -139,69 +139,6 @@ public class IIOUtilTest {
|
||||
assertArrayEquals(expected, output);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subsampleRowPeriod1ByteSameArray() {
|
||||
byte[] inputOutput = {-1, 0, (byte) 0xAA, 0, -1};
|
||||
byte[] expected = {-1, 0, (byte) 0xAA, 0, -1};
|
||||
|
||||
IIOUtil.subsampleRow(inputOutput, 0, inputOutput.length, inputOutput, 0, 1, 8, 1);
|
||||
|
||||
assertArrayEquals(expected, inputOutput);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subsampleRowPeriod1ByteDifferentArray() {
|
||||
byte[] input = {-1, 0, (byte) 0xAA, 0, -1};
|
||||
byte[] output = new byte[input.length];
|
||||
byte[] expected = {-1, 0, (byte) 0xAA, 0, -1};
|
||||
|
||||
IIOUtil.subsampleRow(input, 0, input.length, output, 0, 1, 8, 1);
|
||||
|
||||
assertArrayEquals(expected, output);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subsampleRowPeriod1ShortSameArray() {
|
||||
short[] inputOutput = {-1, 0, (short) 0xAA77, 0, -1};
|
||||
short[] expected = {-1, 0, (short) 0xAA77, 0, -1};
|
||||
|
||||
IIOUtil.subsampleRow(inputOutput, 0, inputOutput.length, inputOutput, 0, 4, 4, 1);
|
||||
|
||||
assertArrayEquals(expected, inputOutput);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subsampleRowPeriod1ShortDifferentArray() {
|
||||
short[] input = {-1, 0, (short) 0xAA77, 0, -1};
|
||||
short[] output = new short[input.length];
|
||||
short[] expected = {-1, 0, (short) 0xAA77, 0, -1};
|
||||
|
||||
IIOUtil.subsampleRow(input, 0, input.length, output, 0, 1, 16, 1);
|
||||
|
||||
assertArrayEquals(expected, output);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subsampleRowPeriod1IntSameArray() {
|
||||
int[] inputOutput = {-1, 0, 0xAA997755, 0, -1};
|
||||
int[] expected = {-1, 0, 0xAA997755, 0, -1};
|
||||
|
||||
IIOUtil.subsampleRow(inputOutput, 0, inputOutput.length, inputOutput, 0, 1, 32, 1);
|
||||
|
||||
assertArrayEquals(expected, inputOutput);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subsampleRowPeriod1IntDifferentArray() {
|
||||
int[] input = {-1, 0, 0xAA997755, 0, -1};
|
||||
int[] output = new int[input.length];
|
||||
int[] expected = {-1, 0, 0xAA997755, 0, -1};
|
||||
|
||||
IIOUtil.subsampleRow(input, 0, input.length, output, 0, 4, 8, 1);
|
||||
|
||||
assertArrayEquals(expected, output);
|
||||
}
|
||||
|
||||
private int divCeil(int numerator, int denominator) {
|
||||
return (numerator + denominator - 1) / denominator;
|
||||
}
|
||||
|
||||
+48
-58
@@ -31,7 +31,6 @@
|
||||
package com.twelvemonkeys.imageio.util;
|
||||
|
||||
import com.twelvemonkeys.imageio.stream.URLImageInputStreamSpi;
|
||||
import com.twelvemonkeys.lang.Validate;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
@@ -39,18 +38,14 @@ import org.mockito.InOrder;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.*;
|
||||
import javax.imageio.event.IIOReadProgressListener;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.spi.IIORegistry;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.awt.*;
|
||||
import java.awt.geom.*;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.image.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -58,7 +53,6 @@ import java.lang.reflect.ParameterizedType;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
@@ -608,7 +602,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
||||
assertReadWithSourceRegionParamEqualImage(new Rectangle(3, 3, 9, 9), getTestData().get(0), 0);
|
||||
}
|
||||
|
||||
protected void assertReadWithSourceRegionParamEqualImage(final Rectangle r, final TestData data, @SuppressWarnings("SameParameterValue") final int imageIndex) throws IOException {
|
||||
protected void assertReadWithSourceRegionParamEqualImage(final Rectangle r, final TestData data, final int imageIndex) throws IOException {
|
||||
ImageReader reader = createReader();
|
||||
try (ImageInputStream inputStream = data.getInputStream()) {
|
||||
reader.setInput(inputStream);
|
||||
@@ -1391,8 +1385,6 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
||||
public void testSetDestination() throws IOException {
|
||||
ImageReader reader = createReader();
|
||||
TestData data = getTestData().get(0);
|
||||
Dimension size = data.getDimension(0);
|
||||
|
||||
reader.setInput(data.getInputStream());
|
||||
|
||||
ImageReadParam param = reader.getDefaultReadParam();
|
||||
@@ -1400,7 +1392,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
||||
while (types.hasNext()) {
|
||||
ImageTypeSpecifier type = types.next();
|
||||
|
||||
BufferedImage destination = type.createBufferedImage(size.width, size.height);
|
||||
BufferedImage destination = type.createBufferedImage(50, 50);
|
||||
param.setDestination(destination);
|
||||
|
||||
BufferedImage result = null;
|
||||
@@ -1450,15 +1442,13 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
||||
public void testSetDestinationIllegal() throws IOException {
|
||||
final ImageReader reader = createReader();
|
||||
TestData data = getTestData().get(0);
|
||||
Dimension size = data.getDimension(0);
|
||||
|
||||
reader.setInput(data.getInputStream());
|
||||
|
||||
List<ImageTypeSpecifier> illegalTypes = createIllegalTypes(reader.getImageTypes(0));
|
||||
|
||||
ImageReadParam param = reader.getDefaultReadParam();
|
||||
for (ImageTypeSpecifier illegalType : illegalTypes) {
|
||||
BufferedImage destination = illegalType.createBufferedImage(size.width, size.height);
|
||||
BufferedImage destination = illegalType.createBufferedImage(50, 50);
|
||||
param.setDestination(destination);
|
||||
|
||||
try {
|
||||
@@ -1759,12 +1749,11 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
||||
ImageReader reader = createReader();
|
||||
|
||||
for (TestData testData : getTestDataForAffineTransformOpCompatibility()) {
|
||||
Dimension size = testData.getDimension(0);
|
||||
try (ImageInputStream input = testData.getInputStream()) {
|
||||
reader.setInput(input);
|
||||
|
||||
ImageReadParam param = reader.getDefaultReadParam();
|
||||
param.setSourceRegion(new Rectangle(size.width, size.height));
|
||||
param.setSourceRegion(new Rectangle(min(reader.getWidth(0), 64), min(reader.getHeight(0), 64)));
|
||||
|
||||
BufferedImage originalImage = reader.read(0, param);
|
||||
|
||||
@@ -1839,51 +1828,52 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
||||
private final List<Dimension> sizes;
|
||||
private final List<BufferedImage> images;
|
||||
|
||||
public TestData(final Object input, final Dimension... dimensions) {
|
||||
this(input, Arrays.asList(dimensions), null);
|
||||
public TestData(final Object pInput, final Dimension... pSizes) {
|
||||
this(pInput, Arrays.asList(pSizes), null);
|
||||
}
|
||||
|
||||
public TestData(final Object input, final BufferedImage... images) {
|
||||
this(input, null, Arrays.asList(images));
|
||||
public TestData(final Object pInput, final BufferedImage... pImages) {
|
||||
this(pInput, null, Arrays.asList(pImages));
|
||||
}
|
||||
|
||||
public TestData(final Object input, final List<Dimension> dimensions, final List<BufferedImage> images) {
|
||||
Validate.notNull(input, "input");
|
||||
Validate.isTrue(dimensions != null || images != null, "Need either dimensions or image");
|
||||
|
||||
List<Dimension> combinedDimensions;
|
||||
if (dimensions == null) {
|
||||
// Copy dimensions from images
|
||||
combinedDimensions = new ArrayList<>(images.size());
|
||||
|
||||
for (BufferedImage image : images) {
|
||||
combinedDimensions.add(new Dimension(image.getWidth(), image.getHeight()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Validate equal dimensions
|
||||
if (images != null) {
|
||||
if (images.size() != dimensions.size()) {
|
||||
throw new IllegalArgumentException("Dimensions and images parameter's size differs");
|
||||
}
|
||||
|
||||
for (int i = 0; i < dimensions.size(); i++) {
|
||||
if (!new Dimension(images.get(i).getWidth(), images.get(i).getHeight()).equals(dimensions.get(i))) {
|
||||
throw new IllegalArgumentException("Dimensions and images parameter's dimensions differ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
combinedDimensions = new ArrayList<>(dimensions);
|
||||
public TestData(final Object pInput, final List<Dimension> pSizes, final List<BufferedImage> pImages) {
|
||||
if (pInput == null) {
|
||||
throw new IllegalArgumentException("input == null");
|
||||
}
|
||||
|
||||
this.sizes = Collections.unmodifiableList(combinedDimensions);
|
||||
sizes = new ArrayList<>();
|
||||
images = new ArrayList<>();
|
||||
|
||||
this.images = images != null
|
||||
? Collections.unmodifiableList(new ArrayList<>(images))
|
||||
: Collections.<BufferedImage>emptyList();
|
||||
List<Dimension> sizes = pSizes;
|
||||
if (sizes == null) {
|
||||
sizes = new ArrayList<>();
|
||||
if (pImages != null) {
|
||||
for (BufferedImage image : pImages) {
|
||||
sizes.add(new Dimension(image.getWidth(), image.getHeight()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Need either size or image");
|
||||
}
|
||||
}
|
||||
else if (pImages != null) {
|
||||
if (pImages.size() != pSizes.size()) {
|
||||
throw new IllegalArgumentException("Size parameter and image size differs");
|
||||
}
|
||||
for (int i = 0; i < sizes.size(); i++) {
|
||||
if (!new Dimension(pImages.get(i).getWidth(), pImages.get(i).getHeight()).equals(sizes.get(i))) {
|
||||
throw new IllegalArgumentException("Size parameter and image size differs");
|
||||
}
|
||||
|
||||
this.input = input;
|
||||
}
|
||||
}
|
||||
|
||||
this.sizes.addAll(sizes);
|
||||
if (pImages != null) {
|
||||
images.addAll(pImages);
|
||||
}
|
||||
|
||||
input = pInput;
|
||||
}
|
||||
|
||||
public Object getInput() {
|
||||
@@ -1908,13 +1898,13 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
|
||||
return sizes.size();
|
||||
}
|
||||
|
||||
public Dimension getDimension(final int index) {
|
||||
return sizes.get(index);
|
||||
public Dimension getDimension(final int pIndex) {
|
||||
return sizes.get(pIndex);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public BufferedImage getImage(final int index) {
|
||||
return images.get(index);
|
||||
public BufferedImage getImage(final int pIndex) {
|
||||
return images.get(pIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-35
@@ -39,7 +39,6 @@ import java.awt.color.*;
|
||||
import java.awt.image.*;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertSame;
|
||||
|
||||
public class ImageTypeSpecifiersTest {
|
||||
|
||||
@@ -737,7 +736,6 @@ public class ImageTypeSpecifiersTest {
|
||||
ImageTypeSpecifier fromType = ImageTypeSpecifiers.createFromBufferedImageType(type);
|
||||
|
||||
assertEquals(fromConstructor.getColorModel(), fromType.getColorModel());
|
||||
assertEquals(fromConstructor.getSampleModel(), fromType.getSampleModel());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -749,43 +747,13 @@ public class ImageTypeSpecifiersTest {
|
||||
ImageTypeSpecifier fromImage = ImageTypeSpecifiers.createFromRenderedImage(image);
|
||||
|
||||
assertEquals(fromConstructor.getColorModel(), fromImage.getColorModel());
|
||||
assertEquals(fromConstructor.getSampleModel(), fromImage.getSampleModel());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateFromRenderedImageIndexedBinaryShouldRetainPalette() {
|
||||
IndexColorModel whiteIsZero = new IndexColorModel(1, 2, new int[]{0xFFFFFFFF, 0xFF000000}, 0, false, -1, DataBuffer.TYPE_BYTE);
|
||||
|
||||
BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_BINARY, whiteIsZero);
|
||||
ImageTypeSpecifier fromImage = ImageTypeSpecifiers.createFromRenderedImage(image);
|
||||
|
||||
assertEquals(whiteIsZero, fromImage.getColorModel());
|
||||
assertSame(whiteIsZero, fromImage.getColorModel()); // Note: This can be relaxed to asserting the LUTs are equal
|
||||
assertEquals(image.getSampleModel(), fromImage.getSampleModel());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateFromRenderedImageIndexedShouldRetainPalette() {
|
||||
IndexColorModel palette = new IndexColorModel(4, 16, new int[]{
|
||||
0xFFFFFFFF, 0xFF999999, 0xFF666666, 0xFF333333,
|
||||
0xFF000000, 0xFF00202E, 0xFF003F5C, 0xFF2C4875,
|
||||
0xFF8A508F, 0xFFBC5090, 0xFFFF6361, 0xFFFF8531,
|
||||
0xFFFFA600, 0xFFFFD380, 0xFF74A892, 0xFF008585
|
||||
}, 0, false, -1, DataBuffer.TYPE_BYTE);
|
||||
|
||||
BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_INDEXED, palette);
|
||||
ImageTypeSpecifier fromImage = ImageTypeSpecifiers.createFromRenderedImage(image);
|
||||
|
||||
assertEquals(palette, fromImage.getColorModel());
|
||||
assertSame(palette, fromImage.getColorModel()); // Note: This can be relaxed to asserting the LUTs are equal
|
||||
assertEquals(image.getSampleModel(), fromImage.getSampleModel());
|
||||
}
|
||||
|
||||
private static byte[] createByteLut(final int count) {
|
||||
byte[] lut = new byte[count];
|
||||
for (int i = 0; i < count; i++) {
|
||||
lut[i] = (byte) (i * 255 / count);
|
||||
lut[i] = (byte) count;
|
||||
}
|
||||
return lut;
|
||||
}
|
||||
@@ -794,8 +762,7 @@ public class ImageTypeSpecifiersTest {
|
||||
int[] lut = new int[count];
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
int val = (i * 255 / count);
|
||||
lut[i] = 0xff000000 | val << 16 | val << 8 | val;
|
||||
lut[i] = 0xff000000 | count << 16 | count << 8 | count;
|
||||
}
|
||||
|
||||
return lut;
|
||||
|
||||
+5
-7
@@ -43,17 +43,15 @@ import javax.imageio.spi.IIORegistry;
|
||||
import javax.imageio.spi.ImageWriterSpi;
|
||||
import javax.imageio.stream.ImageOutputStream;
|
||||
import java.awt.*;
|
||||
import java.awt.image.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
/**
|
||||
@@ -110,8 +108,8 @@ public abstract class ImageWriterAbstractTest<T extends ImageWriter> {
|
||||
return getTestData().get(index);
|
||||
}
|
||||
|
||||
protected URL getClassLoaderResource(final String name) {
|
||||
return getClass().getResource(name);
|
||||
protected URL getClassLoaderResource(final String pName) {
|
||||
return getClass().getResource(pName);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
Copyright (c) 2024, 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.
|
||||
|
||||
|
||||
Parts of this software is based on DDSReader by Kenji Sasaki:
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Kenji Sasaki
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,52 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio</artifactId>
|
||||
<version>3.12.0</version>
|
||||
</parent>
|
||||
<artifactId>imageio-dds</artifactId>
|
||||
<name>TwelveMonkeys :: ImageIO :: DDS plugin</name>
|
||||
<description>
|
||||
ImageIO plugin for Microsoft Direct DrawSurface (DDS).
|
||||
</description>
|
||||
|
||||
<properties>
|
||||
<project.jpms.module.name>com.twelvemonkeys.imageio.dds</project.jpms.module.name>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio-core</artifactId>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>imageio-metadata</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Provide-Capability>
|
||||
osgi.serviceloader;
|
||||
osgi.serviceloader=javax.imageio.spi.ImageReaderSpi
|
||||
</Provide-Capability>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Paul Allen, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.dds;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
interface DDS {
|
||||
byte[] MAGIC = new byte[]{'D', 'D', 'S', ' '};
|
||||
int HEADER_SIZE = 124;
|
||||
|
||||
// Header Flags
|
||||
int FLAG_CAPS = 0x1; // Required in every .dds file.
|
||||
int FLAG_HEIGHT = 0x2; // Required in every .dds file.
|
||||
int FLAG_WIDTH = 0x4; // Required in every .dds file.
|
||||
int FLAG_PITCH = 0x8; // Required when pitch is provided for an uncompressed texture.
|
||||
int FLAG_PIXELFORMAT = 0x1000; // Required in every .dds file.
|
||||
int FLAG_MIPMAPCOUNT = 0x20000; // Required in a mipmapped texture.
|
||||
int FLAG_LINEARSIZE = 0x80000; // Required when pitch is provided for a compressed texture.
|
||||
int FLAG_DEPTH = 0x800000; // Required in a depth texture.
|
||||
|
||||
// Pixel Format Flags
|
||||
int PIXEL_FORMAT_FLAG_FOURCC = 0x04;
|
||||
int PIXEL_FORMAT_FLAG_RGB = 0x40;
|
||||
}
|
||||
-177
@@ -1,177 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Paul Allen, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.dds;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.awt.Dimension;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Arrays;
|
||||
|
||||
final class DDSHeader {
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/direct3ddds/dx-graphics-dds-pguide
|
||||
private int flags;
|
||||
|
||||
private int mipMapCount;
|
||||
private Dimension[] dimensions;
|
||||
|
||||
private int pixelFormatFlags;
|
||||
private int fourCC;
|
||||
private int bitCount;
|
||||
private int redMask;
|
||||
private int greenMask;
|
||||
private int blueMask;
|
||||
private int alphaMask;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
static DDSHeader read(final ImageInputStream imageInput) throws IOException {
|
||||
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]
|
||||
if (dwSize != DDS.HEADER_SIZE) {
|
||||
throw new IIOException(String.format("Invalid DDS header size (expected %d): %d", DDS.HEADER_SIZE, dwSize));
|
||||
}
|
||||
|
||||
// Verify flags
|
||||
header.flags = imageInput.readInt(); // [8,11]
|
||||
if (!header.getFlag(DDS.FLAG_CAPS
|
||||
| DDS.FLAG_HEIGHT
|
||||
| DDS.FLAG_WIDTH
|
||||
| DDS.FLAG_PIXELFORMAT)) {
|
||||
throw new IIOException("Required DDS Flag missing in header: " + Integer.toBinaryString(header.flags));
|
||||
}
|
||||
|
||||
// Read Height & Width
|
||||
int dwHeight = imageInput.readInt(); // [12,15]
|
||||
int dwWidth = imageInput.readInt(); // [16,19]
|
||||
|
||||
int dwPitchOrLinearSize = imageInput.readInt(); // [20,23]
|
||||
int dwDepth = imageInput.readInt(); // [24,27]
|
||||
|
||||
// 0 = (unused) or 1 = (1 level), but still one 'base' image
|
||||
header.mipMapCount = Math.max(1, imageInput.readInt()); // [28,31]
|
||||
|
||||
// build dimensions list
|
||||
header.addDimensions(dwWidth, dwHeight);
|
||||
|
||||
byte[] dwReserved1 = new byte[11 * 4]; // [32,75]
|
||||
imageInput.readFully(dwReserved1);
|
||||
|
||||
// DDS_PIXELFORMAT structure
|
||||
int px_dwSize = imageInput.readInt(); // [76,79]
|
||||
|
||||
header.pixelFormatFlags = imageInput.readInt(); // [80,83]
|
||||
header.fourCC = imageInput.readInt(); // [84,87]
|
||||
header.bitCount = imageInput.readInt(); // [88,91]
|
||||
header.redMask = imageInput.readInt(); // [92,95]
|
||||
header.greenMask = imageInput.readInt(); // [96,99]
|
||||
header.blueMask = imageInput.readInt(); // [100,103]
|
||||
header.alphaMask = imageInput.readInt(); // [104,107]
|
||||
|
||||
int dwCaps = imageInput.readInt(); // [108,111]
|
||||
int dwCaps2 = imageInput.readInt(); // [112,115]
|
||||
int dwCaps3 = imageInput.readInt(); // [116,119]
|
||||
int dwCaps4 = imageInput.readInt(); // [120,123]
|
||||
|
||||
int dwReserved2 = imageInput.readInt(); // [124,127]
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
private void addDimensions(int width, int height) {
|
||||
dimensions = new Dimension[mipMapCount];
|
||||
|
||||
int w = width;
|
||||
int h = height;
|
||||
for (int i = 0; i < mipMapCount; i++) {
|
||||
dimensions[i] = new Dimension(w, h);
|
||||
w /= 2;
|
||||
h /= 2;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean getFlag(int mask) {
|
||||
return (flags & mask) != 0;
|
||||
}
|
||||
|
||||
int getWidth(int imageIndex) {
|
||||
int lim = dimensions[imageIndex].width;
|
||||
return (lim <= 0) ? 1 : lim;
|
||||
}
|
||||
|
||||
int getHeight(int imageIndex) {
|
||||
int lim = dimensions[imageIndex].height;
|
||||
return (lim <= 0) ? 1 : lim;
|
||||
}
|
||||
|
||||
int getMipMapCount() {
|
||||
return mipMapCount;
|
||||
}
|
||||
|
||||
int getBitCount() {
|
||||
return bitCount;
|
||||
}
|
||||
|
||||
int getFourCC() {
|
||||
return fourCC;
|
||||
}
|
||||
|
||||
int getPixelFormatFlags() {
|
||||
return pixelFormatFlags;
|
||||
}
|
||||
|
||||
int getRedMask() {
|
||||
return redMask;
|
||||
}
|
||||
|
||||
int getGreenMask() {
|
||||
return greenMask;
|
||||
}
|
||||
|
||||
int getBlueMask() {
|
||||
return blueMask;
|
||||
}
|
||||
|
||||
int getAlphaMask() {
|
||||
return alphaMask;
|
||||
}
|
||||
}
|
||||
-171
@@ -1,171 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Paul Allen, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.dds;
|
||||
|
||||
import static com.twelvemonkeys.imageio.util.IIOUtil.subsampleRow;
|
||||
|
||||
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
|
||||
public final class DDSImageReader extends ImageReaderBase {
|
||||
|
||||
private DDSHeader header;
|
||||
|
||||
public DDSImageReader(final ImageReaderSpi provider) {
|
||||
super(provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetMembers() {
|
||||
header = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth(final int imageIndex) throws IOException {
|
||||
checkBounds(imageIndex);
|
||||
readHeader();
|
||||
|
||||
return header.getWidth(imageIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight(int imageIndex) throws IOException {
|
||||
checkBounds(imageIndex);
|
||||
readHeader();
|
||||
|
||||
return header.getHeight(imageIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumImages(final boolean allowSearch) throws IOException {
|
||||
assertInput();
|
||||
readHeader();
|
||||
|
||||
return header.getMipMapCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageTypeSpecifier getRawImageType(int imageIndex) throws IOException {
|
||||
checkBounds(imageIndex);
|
||||
readHeader();
|
||||
|
||||
// TODO: Implement for the specific formats...
|
||||
return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IOException {
|
||||
return Collections.singletonList(getRawImageType(imageIndex)).iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage read(int imageIndex, ImageReadParam param) throws IOException {
|
||||
checkBounds(imageIndex);
|
||||
readHeader();
|
||||
|
||||
processImageStarted(imageIndex);
|
||||
|
||||
DDSReader dds = new DDSReader(header);
|
||||
int[] pixels = dds.read(imageInput, imageIndex);
|
||||
|
||||
int width = getWidth(imageIndex);
|
||||
int height = getHeight(imageIndex);
|
||||
|
||||
BufferedImage destination = getDestination(param, getImageTypes(imageIndex), width, height);
|
||||
|
||||
Rectangle srcRegion = new Rectangle();
|
||||
Rectangle destRegion = new Rectangle();
|
||||
|
||||
computeRegions(param, width, height, destination, srcRegion, destRegion);
|
||||
|
||||
int srcXStep = param != null ? param.getSourceXSubsampling() : 1;
|
||||
int srcYStep = param != null ? param.getSourceYSubsampling() : 1;
|
||||
int srcMaxY = srcRegion.y + srcRegion.height;
|
||||
|
||||
for (int y = 0, srcY = srcRegion.y, destY = destRegion.y; srcY < srcMaxY; y++, srcY += srcYStep, destY++) {
|
||||
int offset = width * srcY + srcRegion.x;
|
||||
|
||||
subsampleRow(pixels, offset, width, pixels, offset, 4, 8, srcXStep);
|
||||
destination.setRGB(destRegion.x, destY, destRegion.width, 1, pixels, offset, width);
|
||||
|
||||
if (abortRequested()) {
|
||||
processReadAborted();
|
||||
break;
|
||||
}
|
||||
|
||||
processImageProgress(100f * y / destRegion.height);
|
||||
}
|
||||
|
||||
processImageComplete();
|
||||
|
||||
return destination;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IIOMetadata getImageMetadata(int imageIndex) throws IOException {
|
||||
ImageTypeSpecifier imageType = getRawImageType(imageIndex);
|
||||
|
||||
return new DDSMetadata(imageType, header);
|
||||
}
|
||||
|
||||
private void readHeader() throws IOException {
|
||||
if (header == null) {
|
||||
imageInput.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
||||
header = DDSHeader.read(imageInput);
|
||||
|
||||
imageInput.flushBefore(imageInput.getStreamPosition());
|
||||
}
|
||||
|
||||
imageInput.seek(imageInput.getFlushedPosition());
|
||||
}
|
||||
|
||||
public static void main(final String[] args) throws IOException {
|
||||
for (String arg : args) {
|
||||
File file = new File(arg);
|
||||
BufferedImage image = ImageIO.read(file);
|
||||
showIt(image, file.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
-76
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Paul Allen, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.dds;
|
||||
|
||||
import com.twelvemonkeys.imageio.spi.ImageReaderSpiBase;
|
||||
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
||||
public final class DDSImageReaderSpi extends ImageReaderSpiBase {
|
||||
|
||||
public DDSImageReaderSpi() {
|
||||
super(new DDSProviderInfo());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDecodeInput(final Object source) throws IOException {
|
||||
if (!(source instanceof ImageInputStream)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ImageInputStream stream = (ImageInputStream) source;
|
||||
|
||||
stream.mark();
|
||||
|
||||
try {
|
||||
byte[] magic = new byte[DDS.MAGIC.length];
|
||||
stream.readFully(magic);
|
||||
|
||||
return Arrays.equals(DDS.MAGIC, magic);
|
||||
} finally {
|
||||
stream.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageReader createReaderInstance(Object extension) {
|
||||
return new DDSImageReader(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription(Locale locale) {
|
||||
return "Direct DrawSurface (DDS) Image Reader";
|
||||
}
|
||||
}
|
||||
-58
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.dds;
|
||||
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
|
||||
import com.twelvemonkeys.imageio.StandardImageMetadataSupport;
|
||||
|
||||
final class DDSMetadata extends StandardImageMetadataSupport {
|
||||
DDSMetadata(ImageTypeSpecifier type, DDSHeader header) {
|
||||
super(builder(type)
|
||||
.withCompressionTypeName(compressionName(header))
|
||||
.withFormatVersion("1.0")
|
||||
);
|
||||
}
|
||||
|
||||
private static String compressionName(DDSHeader header) {
|
||||
// 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 "None";
|
||||
}
|
||||
}
|
||||
-50
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Paul Allen, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.dds;
|
||||
|
||||
import com.twelvemonkeys.imageio.spi.ReaderWriterProviderInfo;
|
||||
|
||||
final class DDSProviderInfo extends ReaderWriterProviderInfo {
|
||||
DDSProviderInfo() {
|
||||
super(
|
||||
DDSProviderInfo.class,
|
||||
new String[]{"DDS", "dds"},
|
||||
new String[]{"dds"},
|
||||
new String[]{"image/vnd-ms.dds"},
|
||||
"com.twelvemonkeys.imageio.plugins.dds.DDSImageReader",
|
||||
new String[]{"com.twelvemonkeys.imageio.plugins.dds.DDSImageReaderSpi"},
|
||||
null,
|
||||
null,
|
||||
false, null, null, null, null,
|
||||
true, null, null, null, null
|
||||
);
|
||||
}
|
||||
}
|
||||
-609
@@ -1,609 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Paul Allen, 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.
|
||||
*
|
||||
* Based on DDSReader.java:
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015 Kenji Sasaki
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.dds;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* DDSReader.java
|
||||
* <p>
|
||||
* Copyright (c) 2015 Kenji Sasaki
|
||||
* Released under the MIT license.
|
||||
* <a href="https://github.com/npedotnet/DDSReader/blob/master/LICENSE">MIT License</a>
|
||||
* <p>
|
||||
* <a href="https://github.com/npedotnet/DDSReader/blob/master/README.md">English document</a>
|
||||
* <p>
|
||||
* <a href="http://3dtech.jp/wiki/index.php?DDSReader">Japanese document</a>
|
||||
*/
|
||||
final class DDSReader {
|
||||
|
||||
static final Order ARGB_ORDER = new Order(16, 8, 0, 24);
|
||||
|
||||
private final DDSHeader header;
|
||||
|
||||
DDSReader(DDSHeader header) {
|
||||
this.header = header;
|
||||
}
|
||||
|
||||
int[] read(ImageInputStream imageInput, int imageIndex) throws IOException {
|
||||
|
||||
// type
|
||||
DDSType type = getType();
|
||||
|
||||
// offset buffer to index mipmap image
|
||||
byte[] buffer = null;
|
||||
for (int i = 0; i <= imageIndex; i++) {
|
||||
int len = getLength(type, i);
|
||||
buffer = new byte[len];
|
||||
imageInput.readFully(buffer);
|
||||
}
|
||||
|
||||
int width = header.getWidth(imageIndex);
|
||||
int height = header.getHeight(imageIndex);
|
||||
|
||||
switch (type) {
|
||||
case DXT1:
|
||||
return decodeDXT1(width, height, buffer);
|
||||
case DXT2:
|
||||
return decodeDXT2(width, height, buffer);
|
||||
case DXT3:
|
||||
return decodeDXT3(width, height, buffer);
|
||||
case DXT4:
|
||||
return decodeDXT4(width, height, buffer);
|
||||
case DXT5:
|
||||
return decodeDXT5(width, height, buffer);
|
||||
case A1R5G5B5:
|
||||
return readA1R5G5B5(width, height, buffer);
|
||||
case X1R5G5B5:
|
||||
return readX1R5G5B5(width, height, buffer);
|
||||
case A4R4G4B4:
|
||||
return readA4R4G4B4(width, height, buffer);
|
||||
case X4R4G4B4:
|
||||
return readX4R4G4B4(width, height, buffer);
|
||||
case R5G6B5:
|
||||
return readR5G6B5(width, height, buffer);
|
||||
case R8G8B8:
|
||||
return readR8G8B8(width, height, buffer);
|
||||
case A8B8G8R8:
|
||||
return readA8B8G8R8(width, height, buffer);
|
||||
case X8B8G8R8:
|
||||
return readX8B8G8R8(width, height, buffer);
|
||||
case A8R8G8B8:
|
||||
return readA8R8G8B8(width, height, buffer);
|
||||
case X8R8G8B8:
|
||||
return readX8R8G8B8(width, height, buffer);
|
||||
default:
|
||||
throw new IIOException("Unsupported type: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
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 height = header.getHeight(imageIndex);
|
||||
|
||||
switch (type) {
|
||||
case DXT1:
|
||||
return 8 * ((width + 3) / 4) * ((height + 3) / 4);
|
||||
case DXT2:
|
||||
case DXT3:
|
||||
case DXT4:
|
||||
case DXT5:
|
||||
return 16 * ((width + 3) / 4) * ((height + 3) / 4);
|
||||
case A1R5G5B5:
|
||||
case X1R5G5B5:
|
||||
case A4R4G4B4:
|
||||
case X4R4G4B4:
|
||||
case R5G6B5:
|
||||
case R8G8B8:
|
||||
case A8B8G8R8:
|
||||
case X8B8G8R8:
|
||||
case A8R8G8B8:
|
||||
case X8R8G8B8:
|
||||
return (type.value() & 0xFF) * width * height;
|
||||
default:
|
||||
throw new IIOException("Unknown type: " + Integer.toHexString(type.value()));
|
||||
}
|
||||
}
|
||||
|
||||
private static int[] decodeDXT1(int width, int height, byte[] buffer) {
|
||||
int[] pixels = new int[width * height];
|
||||
int index = 0;
|
||||
int w = (width + 3) / 4;
|
||||
int h = (height + 3) / 4;
|
||||
for (int i = 0; i < h; i++) {
|
||||
for (int j = 0; j < w; j++) {
|
||||
int c0 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8;
|
||||
index += 2;
|
||||
int c1 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8;
|
||||
index += 2;
|
||||
for (int k = 0; k < 4; k++) {
|
||||
if (4 * i + k >= height) break;
|
||||
int t0 = (buffer[index] & 0x03);
|
||||
int t1 = (buffer[index] & 0x0C) >> 2;
|
||||
int t2 = (buffer[index] & 0x30) >> 4;
|
||||
int t3 = (buffer[index++] & 0xC0) >> 6;
|
||||
pixels[4 * width * i + 4 * j + width * k ] = getDXTColor(c0, c1, 0xFF, t0);
|
||||
if (4 * j + 1 >= width) continue;
|
||||
pixels[4 * width * i + 4 * j + width * k + 1] = getDXTColor(c0, c1, 0xFF, t1);
|
||||
if (4 * j + 2 >= width) continue;
|
||||
pixels[4 * width * i + 4 * j + width * k + 2] = getDXTColor(c0, c1, 0xFF, t2);
|
||||
if (4 * j + 3 >= width) continue;
|
||||
pixels[4 * width * i + 4 * j + width * k + 3] = getDXTColor(c0, c1, 0xFF, t3);
|
||||
}
|
||||
}
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
|
||||
private static int[] decodeDXT2(int width, int height, byte[] buffer) {
|
||||
return decodeDXT3(width, height, buffer);
|
||||
}
|
||||
|
||||
private static int[] decodeDXT3(int width, int height, byte[] buffer) {
|
||||
int index = 0;
|
||||
int w = (width + 3) / 4;
|
||||
int h = (height + 3) / 4;
|
||||
int[] pixels = new int[width * height];
|
||||
int[] alphaTable = new int[16];
|
||||
for (int i = 0; i < h; i++) {
|
||||
for (int j = 0; j < w; j++) {
|
||||
// create alpha table(4bit to 8bit)
|
||||
for (int k = 0; k < 4; k++) {
|
||||
int a0 = (buffer[index++] & 0xFF);
|
||||
int a1 = (buffer[index++] & 0xFF);
|
||||
// 4bit alpha to 8bit alpha
|
||||
alphaTable[4 * k ] = 17 * ((a0 & 0xF0) >> 4);
|
||||
alphaTable[4 * k + 1] = 17 * (a0 & 0x0F);
|
||||
alphaTable[4 * k + 2] = 17 * ((a1 & 0xF0) >> 4);
|
||||
alphaTable[4 * k + 3] = 17 * (a1 & 0x0F);
|
||||
}
|
||||
int c0 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8;
|
||||
index += 2;
|
||||
int c1 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8;
|
||||
index += 2;
|
||||
for (int k = 0; k < 4; k++) {
|
||||
if (4 * i + k >= height) break;
|
||||
int t0 = (buffer[index] & 0x03);
|
||||
int t1 = (buffer[index] & 0x0C) >> 2;
|
||||
int t2 = (buffer[index] & 0x30) >> 4;
|
||||
int t3 = (buffer[index++] & 0xC0) >> 6;
|
||||
pixels[4 * width * i + 4 * j + width * k ] = getDXTColor(c0, c1, alphaTable[4 * k ], t0);
|
||||
if (4 * j + 1 >= width) continue;
|
||||
pixels[4 * width * i + 4 * j + width * k + 1] = getDXTColor(c0, c1, alphaTable[4 * k + 1], t1);
|
||||
if (4 * j + 2 >= width) continue;
|
||||
pixels[4 * width * i + 4 * j + width * k + 2] = getDXTColor(c0, c1, alphaTable[4 * k + 2], t2);
|
||||
if (4 * j + 3 >= width) continue;
|
||||
pixels[4 * width * i + 4 * j + width * k + 3] = getDXTColor(c0, c1, alphaTable[4 * k + 3], t3);
|
||||
}
|
||||
}
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
|
||||
private static int[] decodeDXT4(int width, int height, byte[] buffer) {
|
||||
return decodeDXT5(width, height, buffer);
|
||||
}
|
||||
|
||||
private static int[] decodeDXT5(int width, int height, byte[] buffer) {
|
||||
int index = 0;
|
||||
int w = (width + 3) / 4;
|
||||
int h = (height + 3) / 4;
|
||||
int[] pixels = new int[width * height];
|
||||
int[] alphaTable = new int[16];
|
||||
for (int i = 0; i < h; i++) {
|
||||
for (int j = 0; j < w; j++) {
|
||||
// create alpha table
|
||||
int a0 = (buffer[index++] & 0xFF);
|
||||
int a1 = (buffer[index++] & 0xFF);
|
||||
int b0 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8 | (buffer[index + 2] & 0xFF) << 16;
|
||||
index += 3;
|
||||
int b1 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8 | (buffer[index + 2] & 0xFF) << 16;
|
||||
index += 3;
|
||||
alphaTable[0] = b0 & 0x07;
|
||||
alphaTable[1] = (b0 >> 3) & 0x07;
|
||||
alphaTable[2] = (b0 >> 6) & 0x07;
|
||||
alphaTable[3] = (b0 >> 9) & 0x07;
|
||||
alphaTable[4] = (b0 >> 12) & 0x07;
|
||||
alphaTable[5] = (b0 >> 15) & 0x07;
|
||||
alphaTable[6] = (b0 >> 18) & 0x07;
|
||||
alphaTable[7] = (b0 >> 21) & 0x07;
|
||||
alphaTable[8] = b1 & 0x07;
|
||||
alphaTable[9] = (b1 >> 3) & 0x07;
|
||||
alphaTable[10] = (b1 >> 6) & 0x07;
|
||||
alphaTable[11] = (b1 >> 9) & 0x07;
|
||||
alphaTable[12] = (b1 >> 12) & 0x07;
|
||||
alphaTable[13] = (b1 >> 15) & 0x07;
|
||||
alphaTable[14] = (b1 >> 18) & 0x07;
|
||||
alphaTable[15] = (b1 >> 21) & 0x07;
|
||||
int c0 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8;
|
||||
index += 2;
|
||||
int c1 = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8;
|
||||
index += 2;
|
||||
for (int k = 0; k < 4; k++) {
|
||||
if (4 * i + k >= height) break;
|
||||
int t0 = (buffer[index] & 0x03);
|
||||
int t1 = (buffer[index] & 0x0C) >> 2;
|
||||
int t2 = (buffer[index] & 0x30) >> 4;
|
||||
int t3 = (buffer[index++] & 0xC0) >> 6;
|
||||
pixels[4 * width * i + 4 * j + width * k ] = getDXTColor(c0, c1, getDXT5Alpha(a0, a1, alphaTable[4 * k ]), t0);
|
||||
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);
|
||||
if (4 * j + 2 >= width) continue;
|
||||
pixels[4 * width * i + 4 * j + width * k + 2] = getDXTColor(c0, c1, getDXT5Alpha(a0, a1, alphaTable[4 * k + 2]), t2);
|
||||
if (4 * j + 3 >= width) continue;
|
||||
pixels[4 * width * i + 4 * j + width * k + 3] = getDXTColor(c0, c1, getDXT5Alpha(a0, a1, alphaTable[4 * k + 3]), t3);
|
||||
}
|
||||
}
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
|
||||
private static int[] readA1R5G5B5(int width, int height, byte[] buffer) {
|
||||
int index = 0;
|
||||
int[] pixels = new int[width * height];
|
||||
for (int i = 0; i < height * width; i++) {
|
||||
int rgba = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8;
|
||||
index += 2;
|
||||
int r = BIT5[(rgba & A1R5G5B5_MASKS[0]) >> 10];
|
||||
int g = BIT5[(rgba & A1R5G5B5_MASKS[1]) >> 5];
|
||||
int b = BIT5[(rgba & A1R5G5B5_MASKS[2])];
|
||||
int a = 255 * ((rgba & A1R5G5B5_MASKS[3]) >> 15);
|
||||
pixels[i] = (a << ARGB_ORDER.alphaShift) | (r << ARGB_ORDER.redShift) | (g << ARGB_ORDER.greenShift) | (b << ARGB_ORDER.blueShift);
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
|
||||
private static int[] readX1R5G5B5(int width, int height, byte[] buffer) {
|
||||
int index = 0;
|
||||
int[] pixels = new int[width * height];
|
||||
for (int i = 0; i < height * width; i++) {
|
||||
int rgba = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8;
|
||||
index += 2;
|
||||
int r = BIT5[(rgba & X1R5G5B5_MASKS[0]) >> 10];
|
||||
int g = BIT5[(rgba & X1R5G5B5_MASKS[1]) >> 5];
|
||||
int b = BIT5[(rgba & X1R5G5B5_MASKS[2])];
|
||||
int a = 255;
|
||||
pixels[i] = (a << ARGB_ORDER.alphaShift) | (r << ARGB_ORDER.redShift) | (g << ARGB_ORDER.greenShift) | (b << ARGB_ORDER.blueShift);
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
|
||||
private static int[] readA4R4G4B4(int width, int height, byte[] buffer) {
|
||||
int index = 0;
|
||||
int[] pixels = new int[width * height];
|
||||
for (int i = 0; i < height * width; i++) {
|
||||
int rgba = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8;
|
||||
index += 2;
|
||||
int r = 17 * ((rgba & A4R4G4B4_MASKS[0]) >> 8);
|
||||
int g = 17 * ((rgba & A4R4G4B4_MASKS[1]) >> 4);
|
||||
int b = 17 * ((rgba & A4R4G4B4_MASKS[2]));
|
||||
int a = 17 * ((rgba & A4R4G4B4_MASKS[3]) >> 12);
|
||||
pixels[i] = (a << ARGB_ORDER.alphaShift) | (r << ARGB_ORDER.redShift) | (g << ARGB_ORDER.greenShift) | (b << ARGB_ORDER.blueShift);
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
|
||||
private static int[] readX4R4G4B4(int width, int height, byte[] buffer) {
|
||||
int index = 0;
|
||||
int[] pixels = new int[width * height];
|
||||
for (int i = 0; i < height * width; i++) {
|
||||
int rgba = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8;
|
||||
index += 2;
|
||||
int r = 17 * ((rgba & A4R4G4B4_MASKS[0]) >> 8);
|
||||
int g = 17 * ((rgba & A4R4G4B4_MASKS[1]) >> 4);
|
||||
int b = 17 * ((rgba & A4R4G4B4_MASKS[2]));
|
||||
int a = 255;
|
||||
pixels[i] = (a << ARGB_ORDER.alphaShift) | (r << ARGB_ORDER.redShift) | (g << ARGB_ORDER.greenShift) | (b << ARGB_ORDER.blueShift);
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
|
||||
private static int[] readR5G6B5(int width, int height, byte[] buffer) {
|
||||
int index = 0;
|
||||
int[] pixels = new int[width * height];
|
||||
for (int i = 0; i < height * width; i++) {
|
||||
int rgba = (buffer[index] & 0xFF) | (buffer[index + 1] & 0xFF) << 8;
|
||||
index += 2;
|
||||
int r = BIT5[((rgba & R5G6B5_MASKS[0]) >> 11)];
|
||||
int g = BIT6[((rgba & R5G6B5_MASKS[1]) >> 5)];
|
||||
int b = BIT5[((rgba & R5G6B5_MASKS[2]))];
|
||||
int a = 255;
|
||||
pixels[i] = (a << ARGB_ORDER.alphaShift) | (r << ARGB_ORDER.redShift) | (g << ARGB_ORDER.greenShift) | (b << ARGB_ORDER.blueShift);
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
|
||||
private static int[] readR8G8B8(int width, int height, byte[] buffer) {
|
||||
int index = 0;
|
||||
int[] pixels = new int[width * height];
|
||||
for (int i = 0; i < height * width; i++) {
|
||||
int b = buffer[index++] & 0xFF;
|
||||
int g = buffer[index++] & 0xFF;
|
||||
int r = buffer[index++] & 0xFF;
|
||||
int a = 255;
|
||||
pixels[i] = (a << ARGB_ORDER.alphaShift) | (r << ARGB_ORDER.redShift) | (g << ARGB_ORDER.greenShift) | (b << ARGB_ORDER.blueShift);
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
|
||||
private static int[] readA8B8G8R8(int width, int height, byte[] buffer) {
|
||||
int index = 0;
|
||||
int[] pixels = new int[width * height];
|
||||
for (int i = 0; i < height * width; i++) {
|
||||
int r = buffer[index++] & 0xFF;
|
||||
int g = buffer[index++] & 0xFF;
|
||||
int b = buffer[index++] & 0xFF;
|
||||
int a = buffer[index++] & 0xFF;
|
||||
pixels[i] = (a << ARGB_ORDER.alphaShift) | (r << ARGB_ORDER.redShift) | (g << ARGB_ORDER.greenShift) | (b << ARGB_ORDER.blueShift);
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
|
||||
private static int[] readX8B8G8R8(int width, int height, byte[] buffer) {
|
||||
int index = 0;
|
||||
int[] pixels = new int[width * height];
|
||||
for (int i = 0; i < height * width; i++) {
|
||||
int r = buffer[index++] & 0xFF;
|
||||
int g = buffer[index++] & 0xFF;
|
||||
int b = buffer[index++] & 0xFF;
|
||||
int a = 255;
|
||||
index++;
|
||||
pixels[i] = (a << ARGB_ORDER.alphaShift) | (r << ARGB_ORDER.redShift) | (g << ARGB_ORDER.greenShift) | (b << ARGB_ORDER.blueShift);
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
|
||||
private static int[] readA8R8G8B8(int width, int height, byte[] buffer) {
|
||||
int index = 0;
|
||||
int[] pixels = new int[width * height];
|
||||
for (int i = 0; i < height * width; i++) {
|
||||
int b = buffer[index++] & 0xFF;
|
||||
int g = buffer[index++] & 0xFF;
|
||||
int r = buffer[index++] & 0xFF;
|
||||
int a = buffer[index++] & 0xFF;
|
||||
pixels[i] = (a << ARGB_ORDER.alphaShift) | (r << ARGB_ORDER.redShift) | (g << ARGB_ORDER.greenShift) | (b << ARGB_ORDER.blueShift);
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
|
||||
private static int[] readX8R8G8B8(int width, int height, byte[] buffer) {
|
||||
int index = 0;
|
||||
int[] pixels = new int[width * height];
|
||||
for (int i = 0; i < height * width; i++) {
|
||||
int b = buffer[index++] & 0xFF;
|
||||
int g = buffer[index++] & 0xFF;
|
||||
int r = buffer[index++] & 0xFF;
|
||||
int a = 255;
|
||||
index++;
|
||||
pixels[i] = (a << ARGB_ORDER.alphaShift) | (r << ARGB_ORDER.redShift) | (g << ARGB_ORDER.greenShift) | (b << ARGB_ORDER.blueShift);
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
|
||||
private static int getDXTColor(int c0, int c1, int a, int t) {
|
||||
switch (t) {
|
||||
case 0:
|
||||
return getDXTColor1(c0, a);
|
||||
case 1:
|
||||
return getDXTColor1(c1, a);
|
||||
case 2:
|
||||
return (c0 > c1) ? getDXTColor2_1(c0, c1, a) : getDXTColor1_1(c0, c1, a);
|
||||
case 3:
|
||||
return (c0 > c1) ? getDXTColor2_1(c1, c0, a) : 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int getDXTColor2_1(int c0, int c1, int a) {
|
||||
// 2*c0/3 + c1/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 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);
|
||||
}
|
||||
|
||||
private static int getDXTColor1_1(int c0, int c1, int a) {
|
||||
// (c0+c1) / 2
|
||||
int r = (BIT5[(c0 & 0xFC00) >> 11] + BIT5[(c1 & 0xFC00) >> 11]) / 2;
|
||||
int g = (BIT6[(c0 & 0x07E0) >> 5] + BIT6[(c1 & 0x07E0) >> 5]) / 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);
|
||||
}
|
||||
|
||||
private static int getDXTColor1(int c, int a) {
|
||||
int r = BIT5[(c & 0xFC00) >> 11];
|
||||
int g = BIT6[(c & 0x07E0) >> 5];
|
||||
int b = BIT5[(c & 0x001F)];
|
||||
return (a << ARGB_ORDER.alphaShift) | (r << ARGB_ORDER.redShift) | (g << ARGB_ORDER.greenShift) | (b << ARGB_ORDER.blueShift);
|
||||
}
|
||||
|
||||
private static int getDXT5Alpha(int a0, int a1, int t) {
|
||||
if (a0 > a1) switch (t) {
|
||||
case 0:
|
||||
return a0;
|
||||
case 1:
|
||||
return a1;
|
||||
case 2:
|
||||
return (6 * a0 + a1) / 7;
|
||||
case 3:
|
||||
return (5 * a0 + 2 * a1) / 7;
|
||||
case 4:
|
||||
return (4 * a0 + 3 * a1) / 7;
|
||||
case 5:
|
||||
return (3 * a0 + 4 * a1) / 7;
|
||||
case 6:
|
||||
return (2 * a0 + 5 * a1) / 7;
|
||||
case 7:
|
||||
return (a0 + 6 * a1) / 7;
|
||||
}
|
||||
else switch (t) {
|
||||
case 0:
|
||||
return a0;
|
||||
case 1:
|
||||
return a1;
|
||||
case 2:
|
||||
return (4 * a0 + a1) / 5;
|
||||
case 3:
|
||||
return (3 * a0 + 2 * a1) / 5;
|
||||
case 4:
|
||||
return (2 * a0 + 3 * a1) / 5;
|
||||
case 5:
|
||||
return (a0 + 4 * a1) / 5;
|
||||
case 6:
|
||||
return 0;
|
||||
case 7:
|
||||
return 255;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// RGBA Masks
|
||||
private static final int[] A1R5G5B5_MASKS = {0x7C00, 0x03E0, 0x001F, 0x8000};
|
||||
private static final int[] X1R5G5B5_MASKS = {0x7C00, 0x03E0, 0x001F, 0x0000};
|
||||
private static final int[] A4R4G4B4_MASKS = {0x0F00, 0x00F0, 0x000F, 0xF000};
|
||||
private static final int[] X4R4G4B4_MASKS = {0x0F00, 0x00F0, 0x000F, 0x0000};
|
||||
private static final int[] R5G6B5_MASKS = {0xF800, 0x07E0, 0x001F, 0x0000};
|
||||
private static final int[] R8G8B8_MASKS = {0xFF0000, 0x00FF00, 0x0000FF, 0x000000};
|
||||
private static final int[] A8B8G8R8_MASKS = {0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000};
|
||||
private static final int[] X8B8G8R8_MASKS = {0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000};
|
||||
private static final int[] A8R8G8B8_MASKS = {0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000};
|
||||
private static final int[] X8R8G8B8_MASKS = {0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000};
|
||||
|
||||
// BIT4 = 17 * index;
|
||||
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};
|
||||
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};
|
||||
|
||||
private static final class Order {
|
||||
Order(int redShift, int greenShift, int blueShift, int alphaShift) {
|
||||
this.redShift = redShift;
|
||||
this.greenShift = greenShift;
|
||||
this.blueShift = blueShift;
|
||||
this.alphaShift = alphaShift;
|
||||
}
|
||||
|
||||
public int redShift;
|
||||
public int greenShift;
|
||||
public int blueShift;
|
||||
public int alphaShift;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Paul Allen, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.dds;
|
||||
|
||||
enum DDSType {
|
||||
|
||||
DXT1(0x31545844),
|
||||
DXT2(0x32545844),
|
||||
DXT3(0x33545844),
|
||||
DXT4(0x34545844),
|
||||
DXT5(0x35545844),
|
||||
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);
|
||||
|
||||
private final int value;
|
||||
|
||||
DDSType(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int value() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static DDSType valueOf(int value) {
|
||||
for (DDSType type : DDSType.values()) {
|
||||
if (value == type.value()) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(String.format("Unknown type: 0x%08x", value));
|
||||
}
|
||||
}
|
||||
-1
@@ -1 +0,0 @@
|
||||
com.twelvemonkeys.imageio.plugins.dds.DDSImageReaderSpi
|
||||
-107
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.dds;
|
||||
|
||||
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
||||
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import java.awt.Dimension;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class DDSImageReaderTest extends ImageReaderAbstractTest<DDSImageReader> {
|
||||
@Override
|
||||
protected ImageReaderSpi createProvider() {
|
||||
return new DDSImageReaderSpi();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<TestData> getTestData() {
|
||||
Dimension dim256 = new Dimension(256, 256);
|
||||
Dimension dim128 = new Dimension(128, 128);
|
||||
Dimension dim64 = new Dimension(64, 64);
|
||||
Dimension dim32 = new Dimension(32, 32);
|
||||
Dimension dim16 = new Dimension(16, 16);
|
||||
Dimension dim8 = new Dimension(8, 8);
|
||||
Dimension dim4 = new Dimension(4, 4);
|
||||
Dimension dim2 = new Dimension(2, 2);
|
||||
Dimension dim1 = new Dimension(1, 1);
|
||||
|
||||
return Arrays.asList(
|
||||
new TestData(getClassLoaderResource("/dds/dds_A1R5G5B5.dds"), dim256),
|
||||
new TestData(getClassLoaderResource("/dds/dds_A1R5G5B5_mipmap.dds"), dim256, dim128, dim64, dim32, dim16, dim8, dim4, dim2, dim1),
|
||||
new TestData(getClassLoaderResource("/dds/dds_A4R4G4B4.dds"), dim256),
|
||||
new TestData(getClassLoaderResource("/dds/dds_A4R4G4B4_mipmap.dds"), dim256, dim128, dim64),
|
||||
new TestData(getClassLoaderResource("/dds/dds_A8B8G8R8.dds"), dim256),
|
||||
new TestData(getClassLoaderResource("/dds/dds_A8B8G8R8_mipmap.dds"), dim256, dim128, dim64),
|
||||
new TestData(getClassLoaderResource("/dds/dds_A8R8G8B8.dds"), dim256),
|
||||
new TestData(getClassLoaderResource("/dds/dds_A8R8G8B8_mipmap.dds"), dim256, dim128, dim64),
|
||||
new TestData(getClassLoaderResource("/dds/dds_DXT1.dds"), dim256),
|
||||
new TestData(getClassLoaderResource("/dds/dds_DXT1_mipmap.dds"), dim256, dim128, dim64),
|
||||
new TestData(getClassLoaderResource("/dds/dds_DXT2.dds"), dim256),
|
||||
new TestData(getClassLoaderResource("/dds/dds_DXT2_mipmap.dds"), dim256, dim128, dim64),
|
||||
new TestData(getClassLoaderResource("/dds/dds_DXT3.dds"), dim256),
|
||||
new TestData(getClassLoaderResource("/dds/dds_DXT3_mipmap.dds"), dim256, dim128, dim64),
|
||||
new TestData(getClassLoaderResource("/dds/dds_DXT4.dds"), dim256),
|
||||
new TestData(getClassLoaderResource("/dds/dds_DXT4_mipmap.dds"), dim256, dim128, dim64),
|
||||
new TestData(getClassLoaderResource("/dds/dds_DXT5.dds"), dim256),
|
||||
new TestData(getClassLoaderResource("/dds/dds_DXT5_mipmap.dds"), dim256, dim128, dim64),
|
||||
new TestData(getClassLoaderResource("/dds/dds_R5G6B5.dds"), dim256),
|
||||
new TestData(getClassLoaderResource("/dds/dds_R5G6B5_mipmap.dds"), dim256, dim128, dim64),
|
||||
new TestData(getClassLoaderResource("/dds/dds_R8G8B8.dds"), dim256),
|
||||
new TestData(getClassLoaderResource("/dds/dds_R8G8B8_mipmap.dds"), dim256, dim128, dim64),
|
||||
new TestData(getClassLoaderResource("/dds/dds_X1R5G5B5.dds"), dim256),
|
||||
new TestData(getClassLoaderResource("/dds/dds_X1R5G5B5_mipmap.dds"), dim256, dim128, dim64),
|
||||
new TestData(getClassLoaderResource("/dds/dds_X4R4G4B4.dds"), dim256),
|
||||
new TestData(getClassLoaderResource("/dds/dds_X4R4G4B4_mipmap.dds"), dim256, dim128, dim64),
|
||||
new TestData(getClassLoaderResource("/dds/dds_X8B8G8R8.dds"), dim256),
|
||||
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_mipmap.dds"), dim256, dim128, dim64)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getFormatNames() {
|
||||
return Arrays.asList("DDS", "dds");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getSuffixes() {
|
||||
return Collections.singletonList("dds");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<String> getMIMETypes() {
|
||||
return Collections.singletonList("image/vnd-ms.dds");
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user