Compare commits

...

221 Commits

Author SHA1 Message Date
Harald Kuhr 666e0ef94a [maven-release-plugin] prepare for next development iteration 2023-11-07 20:24:45 +01:00
Harald Kuhr b58c4ba5dd [maven-release-plugin] prepare release twelvemonkeys-3.10.1 2023-11-07 20:24:40 +01:00
Harald Kuhr 6328862e4f Set versions to 3.10.1-SNAPSHOT 2023-11-07 20:17:30 +01:00
Harald Kuhr a95235b422 #860: Fix regression in reading broken PackBits stream. 2023-11-07 14:04:28 +01:00
dependabot[bot] 9f4b09fc7d Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.6.0 to 3.6.2
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.6.0 to 3.6.2.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.6.0...maven-javadoc-plugin-3.6.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-07 10:08:53 +01:00
dependabot[bot] 03455f0132 Bump org.apache.maven.plugins:maven-surefire-report-plugin
Bumps [org.apache.maven.plugins:maven-surefire-report-plugin](https://github.com/apache/maven-surefire) from 3.2.1 to 3.2.2.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.2.1...surefire-3.2.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-surefire-report-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-07 10:08:40 +01:00
dependabot[bot] ac5779d8d6 Bump org.apache.maven.plugins:maven-surefire-plugin from 3.2.1 to 3.2.2
Bumps [org.apache.maven.plugins:maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.2.1 to 3.2.2.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.2.1...surefire-3.2.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-surefire-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-07 09:59:54 +01:00
dependabot[bot] fef8ff3aab Bump org.apache.maven.plugins:maven-pmd-plugin from 3.21.0 to 3.21.2
Bumps [org.apache.maven.plugins:maven-pmd-plugin](https://github.com/apache/maven-pmd-plugin) from 3.21.0 to 3.21.2.
- [Release notes](https://github.com/apache/maven-pmd-plugin/releases)
- [Commits](https://github.com/apache/maven-pmd-plugin/compare/maven-pmd-plugin-3.21.0...maven-pmd-plugin-3.21.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-pmd-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-03 10:07:49 +01:00
Steinar Bang a9e4b2e262 Change maven-bundle-plugin config to correctly export ImageWriterSpi services 2023-11-02 09:48:01 +01:00
dependabot[bot] 7147e2dfb1 Bump github/codeql-action from 2.22.4 to 2.22.5 in /.github/workflows
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.22.4 to 2.22.5.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/49abf0ba24d0b7953cb586944e918a0b92074c80...74483a38d39275f33fcff5f35b679b5ca4a26a99)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-30 10:09:56 +01:00
dependabot[bot] 1680fadf83 Bump commons-io:commons-io from 2.14.0 to 2.15.0
Bumps commons-io:commons-io from 2.14.0 to 2.15.0.

---
updated-dependencies:
- dependency-name: commons-io:commons-io
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-26 11:04:08 +02:00
Harald Kuhr d1df8c13ed Remove outdated TODO 2023-10-25 22:14:54 +02:00
Harald Kuhr 031937fe99 #852 JPEG: Preserve existing metadata when writing CMYK data 2023-10-25 22:14:05 +02:00
dependabot[bot] 24c473ae45 Bump org.apache.maven.plugins:maven-surefire-report-plugin
Bumps [org.apache.maven.plugins:maven-surefire-report-plugin](https://github.com/apache/maven-surefire) from 3.1.2 to 3.2.1.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.1.2...surefire-3.2.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-surefire-report-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-24 11:26:45 +02:00
dependabot[bot] 57941cb638 Bump org.apache.maven.plugins:maven-surefire-plugin from 3.1.2 to 3.2.1
Bumps [org.apache.maven.plugins:maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.1.2 to 3.2.1.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.1.2...surefire-3.2.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-surefire-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-24 11:26:24 +02:00
dependabot[bot] d325b6deec Bump org.apache.maven.plugins:maven-checkstyle-plugin
Bumps [org.apache.maven.plugins:maven-checkstyle-plugin](https://github.com/apache/maven-checkstyle-plugin) from 3.3.0 to 3.3.1.
- [Commits](https://github.com/apache/maven-checkstyle-plugin/compare/maven-checkstyle-plugin-3.3.0...maven-checkstyle-plugin-3.3.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-checkstyle-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-24 11:25:52 +02:00
dependabot[bot] 3f67430b2d Bump ossf/scorecard-action from 2.3.0 to 2.3.1 in /.github/workflows
Bumps [ossf/scorecard-action](https://github.com/ossf/scorecard-action) from 2.3.0 to 2.3.1.
- [Release notes](https://github.com/ossf/scorecard-action/releases)
- [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md)
- [Commits](https://github.com/ossf/scorecard-action/compare/483ef80eb98fb506c348f7d62e28055e49fe2398...0864cf19026789058feabb7e87baa5f140aac736)

---
updated-dependencies:
- dependency-name: ossf/scorecard-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-24 11:25:19 +02:00
dependabot[bot] 314071dde8 Bump mikepenz/action-junit-report in /.github/workflows
Bumps [mikepenz/action-junit-report](https://github.com/mikepenz/action-junit-report) from 4.0.2 to 4.0.3.
- [Release notes](https://github.com/mikepenz/action-junit-report/releases)
- [Commits](https://github.com/mikepenz/action-junit-report/compare/7e43ff95fc4d43209637c265c8fca9c8f1c157b5...0831a82caad2465c31c6dd929978f640cb42556c)

---
updated-dependencies:
- dependency-name: mikepenz/action-junit-report
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-23 11:19:36 +02:00
dependabot[bot] 83ad25c2dd Bump github/codeql-action from 2.22.3 to 2.22.4 in /.github/workflows
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.22.3 to 2.22.4.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/0116bc2df50751f9724a2e35ef1f24d22f90e4e1...49abf0ba24d0b7953cb586944e918a0b92074c80)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-23 11:19:12 +02:00
KoenDG d7dae90e2e The original condition of i bigger than mapsize will never be true, since i starts at 0.
The condition should be: i smaller than mapsize, if we want to loop over the mapsize.
2023-10-21 11:06:54 +02:00
Harald Kuhr ad437c2470 Better comment 2023-10-20 22:12:23 +02:00
Harald Kuhr dabc26bdb5 [maven-release-plugin] prepare for next development iteration 2023-10-20 21:25:12 +02:00
Harald Kuhr b441298a9a [maven-release-plugin] prepare release twelvemonkeys-3.10.0 2023-10-20 21:25:06 +02:00
Harald Kuhr 345ca0ac13 POM fixes 2023-10-20 16:53:25 +02:00
Harald Kuhr 9720a931c5 #843: Correctly handle empty image resources section. 2023-10-20 12:27:17 +02:00
dependabot[bot] 4d3f691e6a Bump mikepenz/action-junit-report in /.github/workflows
Bumps [mikepenz/action-junit-report](https://github.com/mikepenz/action-junit-report) from 4.0.1 to 4.0.2.
- [Release notes](https://github.com/mikepenz/action-junit-report/releases)
- [Commits](https://github.com/mikepenz/action-junit-report/compare/0a8a5ba57593d67b2e45de2c543b438412382b7b...7e43ff95fc4d43209637c265c8fca9c8f1c157b5)

---
updated-dependencies:
- dependency-name: mikepenz/action-junit-report
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-20 12:08:47 +02:00
Harald Kuhr 2e0e575183 #841: Filter out incompatible ICC profiles 2023-10-19 11:10:47 +02:00
Harald Kuhr 2c7c47b158 #837: Now uses last app segment for color space detection. 2023-10-18 16:52:47 +02:00
Harald Kuhr 57680f1bec Change from java 21-ea to 21 (official temurin build is out) 2023-10-18 16:33:11 +02:00
Harald Kuhr 8dc83c4e9e Remove JDK 20 now that we have 21. 2023-10-18 16:20:31 +02:00
dependabot[bot] 929bea6b6b Bump actions/checkout from 4.1.0 to 4.1.1 in /.github/workflows
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/8ade135a41bc03ea155e62e844d188df1ea18608...b4ffde65f46336ab88eb53be808477a3936bae11)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-18 11:58:04 +02:00
dependabot[bot] 699662d054 Bump github/codeql-action from 2.22.2 to 2.22.3 in /.github/workflows
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.22.2 to 2.22.3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/d90b8d79de6dc1f58e83a1499aa58d6c93dc28de...0116bc2df50751f9724a2e35ef1f24d22f90e4e1)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-16 11:58:00 +02:00
dependabot[bot] 1bebee1851 Bump github/codeql-action from 2.22.1 to 2.22.2 in /.github/workflows
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.22.1 to 2.22.2.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/fdcae64e1484d349b3366718cdfef3d404390e85...d90b8d79de6dc1f58e83a1499aa58d6c93dc28de)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-13 10:53:29 +02:00
dependabot[bot] b0e8dd86bb Bump github/codeql-action from 2.22.0 to 2.22.1 in /.github/workflows
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.22.0 to 2.22.1.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/2cb752a87e96af96708ab57187ab6372ee1973ab...fdcae64e1484d349b3366718cdfef3d404390e85)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-10 11:06:58 +02:00
dependabot[bot] 5bdb0b5502 Bump ossf/scorecard-action from 2.2.0 to 2.3.0 in /.github/workflows
Bumps [ossf/scorecard-action](https://github.com/ossf/scorecard-action) from 2.2.0 to 2.3.0.
- [Release notes](https://github.com/ossf/scorecard-action/releases)
- [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md)
- [Commits](https://github.com/ossf/scorecard-action/compare/08b4669551908b1024bb425080c797723083c031...483ef80eb98fb506c348f7d62e28055e49fe2398)

---
updated-dependencies:
- dependency-name: ossf/scorecard-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-09 11:41:44 +02:00
dependabot[bot] 85d47528a3 Bump github/codeql-action from 2.21.9 to 2.22.0 in /.github/workflows
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.21.9 to 2.22.0.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/ddccb873888234080b77e9bc2d4764d5ccaaccf9...2cb752a87e96af96708ab57187ab6372ee1973ab)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-09 11:41:25 +02:00
Steinar Bang a7ebd66149 Export all TwelveMonkeys imageio SPI plugins using the osgi.serviceloader capability 2023-10-05 21:52:33 +02:00
Steinar Bang f0a032a7b9 Add Require-Capability header requiring osgi.serviceloader.registrar to all imageio OSGi bundle MANIFEST.MF files 2023-10-05 21:52:33 +02:00
Steinar Bang 690cb064e7 Ignore eclipse .metadata directory 2023-10-05 21:52:33 +02:00
Steinar Bang e65f471a8f Provide Require-Capability and Add-Capability headers for osgi.serviceloader to the imageio-jpeg MANIFEST.MF
This is to make it possible to load the SPI plugin in OSGi.
2023-10-05 21:52:33 +02:00
Steinar Bang f2cc9faaf8 Add maven-bundle-plugin to build to give jar files OSGi manifest headers and make the jar files OSGi bundles, fixes #794 2023-10-05 21:52:33 +02:00
Harald Kuhr 8bd3f4f34a Badge reorganization. 2023-10-05 21:51:01 +02:00
Harald Kuhr be348543d8 Fix possibly flaky test. 2023-10-05 20:30:22 +02:00
Harald Kuhr 80229b8c3c Minor code clean-up. 2023-10-05 20:27:18 +02:00
Harald Kuhr a5ee53569d Added OpenSSF Best Practices badge. 2023-10-05 20:20:11 +02:00
Harald Kuhr c22ada03cd Replace some usages of ImageTypeSpecifier.createFromRenderedImage. 2023-10-05 20:09:37 +02:00
Harald Kuhr b61341ce3b Testing JDK 21-ea 2023-10-05 15:05:30 +02:00
Harald Kuhr e73b0a7bcf Update ci.yml 2023-10-05 15:05:30 +02:00
dependabot[bot] ea9d1c0dc5 Bump github/codeql-action from 2.21.8 to 2.21.9 in /.github/workflows
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.21.8 to 2.21.9.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v2.21.8...ddccb873888234080b77e9bc2d4764d5ccaaccf9)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-04 10:19:14 +02:00
Harald Kuhr e0563ee7dd Fix some easy to fix CodeQL issues 2023-10-03 13:44:51 +02:00
Joyce 44bcd202e8 Update codeql.yml
Signed-off-by: Joyce <joycebrum@google.com>
2023-10-03 12:23:13 +02:00
Joyce 5b57b51ff1 set top level permission to codeql.yml
Signed-off-by: Joyce <joycebrum@google.com>
2023-10-03 12:23:13 +02:00
Joyce 0b5f8a071e Create codeql.yml
Signed-off-by: Joyce <joycebrum@google.com>
2023-10-03 12:23:13 +02:00
dependabot[bot] d3dc578936 Bump commons-io:commons-io from 2.13.0 to 2.14.0
Bumps commons-io:commons-io from 2.13.0 to 2.14.0.

---
updated-dependencies:
- dependency-name: commons-io:commons-io
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-02 11:51:46 +02:00
dependabot[bot] 2ae937b870 Bump mikepenz/action-junit-report in /.github/workflows
Bumps [mikepenz/action-junit-report](https://github.com/mikepenz/action-junit-report) from 4.0.0 to 4.0.1.
- [Release notes](https://github.com/mikepenz/action-junit-report/releases)
- [Commits](https://github.com/mikepenz/action-junit-report/compare/75b84e78b3f0aaea7ed7cf8d1d100d7f97f963ec...0a8a5ba57593d67b2e45de2c543b438412382b7b)

---
updated-dependencies:
- dependency-name: mikepenz/action-junit-report
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-02 11:51:17 +02:00
dependabot[bot] 2a7763299a Bump github/codeql-action from 2.21.8 to 2.21.9 in /.github/workflows
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.21.8 to 2.21.9.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/6a28655e3dcb49cb0840ea372fd6d17733edd8a4...ddccb873888234080b77e9bc2d4764d5ccaaccf9)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-28 13:36:41 +02:00
dependabot[bot] a57a1d35f9 Bump actions/checkout from 4.0.0 to 4.1.0 in /.github/workflows
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.0.0 to 4.1.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/3df4ab11eba7bda6032a0b82a6bb43b11571feac...8ade135a41bc03ea155e62e844d188df1ea18608)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-25 11:15:14 +02:00
dependabot[bot] e618805786 Bump org.apache.maven.plugins:maven-shade-plugin from 3.5.0 to 3.5.1
Bumps [org.apache.maven.plugins:maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.5.0 to 3.5.1.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.5.0...maven-shade-plugin-3.5.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-25 11:05:30 +02:00
Harald Kuhr e3cb923d37 #815: Filter metadata and thumbnails before passing to JPEG delegate. 2023-09-23 16:14:23 +02:00
Harald Kuhr 4513b0c166 Better support for ImageTypeSpecifiers with IndexColorModel. 2023-09-22 11:52:11 +02:00
dependabot[bot] b55d4e8c1b Bump actions/setup-java from 3.12.0 to 3.13.0 in /.github/workflows
Bumps [actions/setup-java](https://github.com/actions/setup-java) from 3.12.0 to 3.13.0.
- [Release notes](https://github.com/actions/setup-java/releases)
- [Commits](https://github.com/actions/setup-java/compare/cd89f46ac9d01407894225f350157564c9c7cee2...0ab4596768b603586c0de567f2430c30f5b0d2b0)

---
updated-dependencies:
- dependency-name: actions/setup-java
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-21 10:52:58 +02:00
dependabot[bot] 399c75f59e Bump github/codeql-action from 2.21.7 to 2.21.8 in /.github/workflows
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.21.7 to 2.21.8.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/04daf014b50eaf774287bf3f0f1869d4b4c4b913...6a28655e3dcb49cb0840ea372fd6d17733edd8a4)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-20 10:46:35 +02:00
dependabot[bot] a7f7d73e2d Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.5.0 to 3.6.0
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.5.0 to 3.6.0.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.5.0...maven-javadoc-plugin-3.6.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-18 11:51:50 +02:00
dependabot[bot] 41a83191b7 Bump github/codeql-action from 2.21.6 to 2.21.7 in /.github/workflows
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.21.6 to 2.21.7.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/701f152f28d4350ad289a5e31435e9ab6169a7ca...04daf014b50eaf774287bf3f0f1869d4b4c4b913)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-15 11:48:36 +02:00
dependabot[bot] 49e805eeb7 Bump github/codeql-action from 2.21.5 to 2.21.6 in /.github/workflows
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.21.5 to 2.21.6.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/00e563ead9f72a8461b24876bee2d0c2e8bd2ee8...701f152f28d4350ad289a5e31435e9ab6169a7ca)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-14 10:37:08 +02:00
dependabot[bot] f426637fdd Bump mikepenz/action-junit-report in /.github/workflows
Bumps [mikepenz/action-junit-report](https://github.com/mikepenz/action-junit-report) from 3.8.0 to 4.0.0.
- [Release notes](https://github.com/mikepenz/action-junit-report/releases)
- [Commits](https://github.com/mikepenz/action-junit-report/compare/150e2f992e4fad1379da2056d1d1c279f520e058...75b84e78b3f0aaea7ed7cf8d1d100d7f97f963ec)

---
updated-dependencies:
- dependency-name: mikepenz/action-junit-report
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-07 11:04:31 +02:00
dependabot[bot] 4081ff1545 Bump actions/upload-artifact from 3.1.2 to 3.1.3 in /.github/workflows
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3.1.2 to 3.1.3.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/0b7f8abb1508181956e8e162db84b466c27e18ce...a8a3f3ad30e3422c9c7b888a15615d19a852ae32)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-07 11:03:42 +02:00
Harald Kuhr ae4fbcc726 Merge pull request #806 from haraldk/dependabot/github_actions/dot-github/workflows/actions/checkout-4.0.0
Bump actions/checkout from 3.6.0 to 4.0.0 in /.github/workflows
2023-09-05 13:54:23 +02:00
dependabot[bot] 66208bfa03 Bump actions/checkout from 3.6.0 to 4.0.0 in /.github/workflows
Bumps [actions/checkout](https://github.com/actions/checkout) from 3.6.0 to 4.0.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/f43a0e5ff2bd294095638e18286ca9a3d1956744...3df4ab11eba7bda6032a0b82a6bb43b11571feac)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-05 09:06:47 +00:00
Harald Kuhr e72255805e Merge pull request #805 from haraldk/dependabot/github_actions/dot-github/workflows/github/codeql-action-2.21.5
Bump github/codeql-action from 2.21.4 to 2.21.5 in /.github/workflows
2023-08-29 10:50:48 +02:00
dependabot[bot] 780ccd7916 Bump github/codeql-action from 2.21.4 to 2.21.5 in /.github/workflows
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.21.4 to 2.21.5.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/a09933a12a80f87b87005513f0abb1494c27a716...00e563ead9f72a8461b24876bee2d0c2e8bd2ee8)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-29 08:20:59 +00:00
Harald Kuhr 957e917281 Merge pull request #803 from haraldk/dependabot/github_actions/dot-github/workflows/actions/checkout-3.6.0
Bump actions/checkout from 3.5.3 to 3.6.0 in /.github/workflows
2023-08-25 10:31:16 +02:00
dependabot[bot] 9daf8337ee Bump actions/checkout from 3.5.3 to 3.6.0 in /.github/workflows
Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.3 to 3.6.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/c85c95e3d7251135ab7dc9ce3241c5835cc595a9...f43a0e5ff2bd294095638e18286ca9a3d1956744)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-25 08:13:57 +00:00
Harald Kuhr 89c104d59f Merge pull request #802 from haraldk/dependabot/maven/batik.version-1.17
Bump batik.version from 1.16 to 1.17
2023-08-23 12:52:34 +02:00
dependabot[bot] 8608ee76c5 Bump batik.version from 1.16 to 1.17
Bumps `batik.version` from 1.16 to 1.17.

Updates `org.apache.xmlgraphics:batik-rasterizer-ext` from 1.16 to 1.17

Updates `org.apache.xmlgraphics:batik-extension` from 1.16 to 1.17

Updates `org.apache.xmlgraphics:batik-anim` from 1.16 to 1.17

Updates `org.apache.xmlgraphics:batik-svggen` from 1.16 to 1.17

Updates `org.apache.xmlgraphics:batik-transcoder` from 1.16 to 1.17

---
updated-dependencies:
- dependency-name: org.apache.xmlgraphics:batik-rasterizer-ext
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: org.apache.xmlgraphics:batik-extension
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: org.apache.xmlgraphics:batik-anim
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: org.apache.xmlgraphics:batik-svggen
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: org.apache.xmlgraphics:batik-transcoder
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-23 10:46:41 +00:00
Harald Kuhr aab2d36e92 Prepare for new Batik version 2023-08-23 12:41:54 +02:00
Harald Kuhr 608b37232d #792: Guard against incorrect JPEG Huffman Table class 2023-08-21 13:10:45 +02:00
Harald Kuhr e3ebf8e0fa Merge pull request #800 from haraldk/dependabot/github_actions/dot-github/workflows/ossf/scorecard-action-2.2.0
Bump ossf/scorecard-action from 2.1.2 to 2.2.0 in /.github/workflows
2023-08-21 11:56:14 +02:00
Harald Kuhr 9af10625a2 Merge pull request #799 from haraldk/dependabot/github_actions/dot-github/workflows/actions/upload-artifact-3.1.2
Bump actions/upload-artifact from 3.1.0 to 3.1.2 in /.github/workflows
2023-08-21 11:56:05 +02:00
Harald Kuhr ccc4e7b411 Merge pull request #798 from haraldk/dependabot/github_actions/dot-github/workflows/actions/checkout-3.5.3
Bump actions/checkout from 3.1.0 to 3.5.3 in /.github/workflows
2023-08-21 11:51:32 +02:00
dependabot[bot] 439323c5e5 Bump actions/checkout from 3.1.0 to 3.5.3 in /.github/workflows
Bumps [actions/checkout](https://github.com/actions/checkout) from 3.1.0 to 3.5.3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3.1.0...c85c95e3d7251135ab7dc9ce3241c5835cc595a9)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-21 09:50:52 +00:00
Harald Kuhr 332e191d0d Merge pull request #797 from haraldk/dependabot/github_actions/dot-github/workflows/github/codeql-action-2.21.4
Bump github/codeql-action from 2.2.4 to 2.21.4 in /.github/workflows
2023-08-21 11:50:12 +02:00
Harald Kuhr 58d1a89028 Merge pull request #790 from haraldk/dependabot/github_actions/dot-github/workflows/actions/setup-java-3.12.0
Bump actions/setup-java from 3.11.0 to 3.12.0 in /.github/workflows
2023-08-21 11:49:57 +02:00
dependabot[bot] 72fe799cc8 Bump ossf/scorecard-action from 2.1.2 to 2.2.0 in /.github/workflows
Bumps [ossf/scorecard-action](https://github.com/ossf/scorecard-action) from 2.1.2 to 2.2.0.
- [Release notes](https://github.com/ossf/scorecard-action/releases)
- [Changelog](https://github.com/ossf/scorecard-action/blob/main/RELEASE.md)
- [Commits](https://github.com/ossf/scorecard-action/compare/e38b1902ae4f44df626f11ba0734b14fb91f8f86...08b4669551908b1024bb425080c797723083c031)

---
updated-dependencies:
- dependency-name: ossf/scorecard-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-21 08:59:55 +00:00
dependabot[bot] 18af213e27 Bump actions/upload-artifact from 3.1.0 to 3.1.2 in /.github/workflows
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3.1.0 to 3.1.2.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/3cea5372237819ed00197afe530f5a7ea3e805c8...0b7f8abb1508181956e8e162db84b466c27e18ce)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-21 08:59:52 +00:00
dependabot[bot] 9d267f352f Bump github/codeql-action from 2.2.4 to 2.21.4 in /.github/workflows
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.2.4 to 2.21.4.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/17573ee1cc1b9d061760f3a006fc4aac4f944fd5...a09933a12a80f87b87005513f0abb1494c27a716)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-21 08:59:46 +00:00
Harald Kuhr f8f6f9f1e4 Merge pull request #796 from joycebrum/master
Add OpenSSF Scorecard Workflow
2023-08-18 16:00:02 +02:00
Joyce 2841d26785 Add scorecard badge to README.md
Signed-off-by: Joyce <joycebrum@google.com>
2023-08-07 15:28:33 -03:00
Joyce 98ae5967ca Create scorecard.yml
Signed-off-by: Joyce <joycebrum@google.com>
2023-08-07 15:26:28 -03:00
dependabot[bot] da9d87a561 Bump actions/setup-java from 3.11.0 to 3.12.0 in /.github/workflows
Bumps [actions/setup-java](https://github.com/actions/setup-java) from 3.11.0 to 3.12.0.
- [Release notes](https://github.com/actions/setup-java/releases)
- [Commits](https://github.com/actions/setup-java/compare/5ffc13f4174014e2d4d4572b3d74c3fa61aeb2c2...cd89f46ac9d01407894225f350157564c9c7cee2)

---
updated-dependencies:
- dependency-name: actions/setup-java
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-25 08:32:19 +00:00
Harald Kuhr d472191926 BMP cleanup 2023-07-19 14:04:27 +02:00
Harald Kuhr a8472170c4 HDR clean-up 2023-07-19 13:24:40 +02:00
Harald Kuhr b2f7cada21 #784 TIFF: No longer return incorrect standard image type for RGB with custom ICC profile 2023-07-17 12:08:43 +02:00
Harald Kuhr 2a4c152c3d #786 TIFF: No longer create custom Inflater, to avoid resource leak 2023-07-17 12:04:45 +02:00
Harald Kuhr 660932b7e7 Merge pull request #787 from haraldk/dependabot/github_actions/dot-github/workflows/mikepenz/action-junit-report-3.8.0
Bump mikepenz/action-junit-report from 3.7.8 to 3.8.0 in /.github/workflows
2023-07-17 10:31:12 +02:00
dependabot[bot] d0a17ff3b3 Bump mikepenz/action-junit-report in /.github/workflows
Bumps [mikepenz/action-junit-report](https://github.com/mikepenz/action-junit-report) from 3.7.8 to 3.8.0.
- [Release notes](https://github.com/mikepenz/action-junit-report/releases)
- [Commits](https://github.com/mikepenz/action-junit-report/compare/baaeba622e27b396105f35ec9ec4ee89ffcbd306...150e2f992e4fad1379da2056d1d1c279f520e058)

---
updated-dependencies:
- dependency-name: mikepenz/action-junit-report
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-07-17 08:25:39 +00:00
Harald Kuhr 4259903bdd Merge pull request #781 from haraldk/dependabot/github_actions/dot-github/workflows/mikepenz/action-junit-report-3.7.8
Bump mikepenz/action-junit-report from 3.7.7 to 3.7.8 in /.github/workflows
2023-06-22 11:31:12 +02:00
dependabot[bot] 3018d2a342 Bump mikepenz/action-junit-report in /.github/workflows
Bumps [mikepenz/action-junit-report](https://github.com/mikepenz/action-junit-report) from 3.7.7 to 3.7.8.
- [Release notes](https://github.com/mikepenz/action-junit-report/releases)
- [Commits](https://github.com/mikepenz/action-junit-report/compare/c0e4b81aaa0067314a2d0d06e19b512c9d8af4f5...baaeba622e27b396105f35ec9ec4ee89ffcbd306)

---
updated-dependencies:
- dependency-name: mikepenz/action-junit-report
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-22 09:08:28 +00:00
Harald Kuhr 8f94318f28 Merge pull request #780 from haraldk/dependabot/maven/org.apache.maven.plugins-maven-shade-plugin-3.5.0
Bump maven-shade-plugin from 3.4.1 to 3.5.0
2023-06-19 12:08:24 +02:00
dependabot[bot] 60b7151eb6 Bump maven-shade-plugin from 3.4.1 to 3.5.0
Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.4.1 to 3.5.0.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.4.1...maven-shade-plugin-3.5.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-19 09:11:11 +00:00
Harald Kuhr 8ad21307e8 Merge pull request #779 from haraldk/dependabot/github_actions/dot-github/workflows/actions/checkout-3.5.3
Bump actions/checkout from 3.5.2 to 3.5.3 in /.github/workflows
2023-06-12 12:03:24 +02:00
dependabot[bot] 8c854f1e20 Bump actions/checkout from 3.5.2 to 3.5.3 in /.github/workflows
Bumps [actions/checkout](https://github.com/actions/checkout) from 3.5.2 to 3.5.3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/8e5e7e5ab8b370d6c329ec480221332ada57f0ab...c85c95e3d7251135ab7dc9ce3241c5835cc595a9)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-12 09:09:29 +00:00
Harald Kuhr 1445ff2533 Merge pull request #778 from haraldk/dependabot/maven/commons-io-commons-io-2.13.0
Bump commons-io from 2.12.0 to 2.13.0
2023-06-08 12:13:03 +02:00
dependabot[bot] e8f1e80d4e Bump commons-io from 2.12.0 to 2.13.0
Bumps commons-io from 2.12.0 to 2.13.0.

---
updated-dependencies:
- dependency-name: commons-io:commons-io
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-08 09:17:37 +00:00
Harald Kuhr 18e29e9ed5 Merge pull request #777 from haraldk/dependabot/maven/org.apache.maven.plugins-maven-surefire-report-plugin-3.1.2
Bump maven-surefire-report-plugin from 3.1.0 to 3.1.2
2023-06-07 11:59:39 +02:00
Harald Kuhr ec4003b1c1 Merge pull request #776 from haraldk/dependabot/maven/org.apache.maven.plugins-maven-surefire-plugin-3.1.2
Bump maven-surefire-plugin from 3.1.0 to 3.1.2
2023-06-07 11:59:27 +02:00
dependabot[bot] 164b8db988 Bump maven-surefire-report-plugin from 3.1.0 to 3.1.2
Bumps [maven-surefire-report-plugin](https://github.com/apache/maven-surefire) from 3.1.0 to 3.1.2.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.1.0...surefire-3.1.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-surefire-report-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-07 09:09:31 +00:00
dependabot[bot] 21feace385 Bump maven-surefire-plugin from 3.1.0 to 3.1.2
Bumps [maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.1.0 to 3.1.2.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.1.0...surefire-3.1.2)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-surefire-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-07 09:09:19 +00:00
Harald Kuhr ba1f754611 #722 Fix WebP animation transparent frame issue 2023-06-05 12:36:38 +02:00
Harald Kuhr 822b5da631 #772 Fix WebP animation transparent frame issue 2023-06-05 11:41:03 +02:00
Harald Kuhr c785f6932f Merge remote-tracking branch 'origin/master' 2023-06-05 11:38:06 +02:00
Harald Kuhr 43e2a27c7f Merge pull request #774 from haraldk/dependabot/maven/org.apache.maven.plugins-maven-release-plugin-3.0.1
Bump maven-release-plugin from 3.0.0 to 3.0.1
2023-06-05 11:23:23 +02:00
dependabot[bot] 9d50acd2fe Bump maven-release-plugin from 3.0.0 to 3.0.1
Bumps [maven-release-plugin](https://github.com/apache/maven-release) from 3.0.0 to 3.0.1.
- [Release notes](https://github.com/apache/maven-release/releases)
- [Commits](https://github.com/apache/maven-release/compare/maven-release-3.0.0...maven-release-3.0.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-release-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-05 09:10:54 +00:00
Harald Kuhr ba73a308d6 Merge pull request #771 from daaaaa/master
PSD: Adding parsing for 'lsdk' (undocumented) additional layer information
2023-05-30 09:32:31 +02:00
Davide Tantillo 20cd259abd PSD: Adding parsing for 'lsdk' (undocumented) additional layer information key that represents a 'nested section diverder setting' 2023-05-30 09:18:47 +02:00
Harald Kuhr 033a1423ff Merge pull request #770 from haraldk/dependabot/maven/org.sonatype.plugins-nexus-staging-maven-plugin-1.6.13
Bump nexus-staging-maven-plugin from 1.6.8 to 1.6.13
2023-05-25 14:54:16 +02:00
Harald Kuhr 7c8c520006 Merge pull request #769 from haraldk/dependabot/maven/org.apache.maven.scm-maven-scm-provider-gitexe-2.0.1
Bump maven-scm-provider-gitexe from 1.11.2 to 2.0.1
2023-05-25 14:54:07 +02:00
Harald Kuhr 9162458e36 Merge pull request #765 from haraldk/dependabot/maven/org.apache.maven.plugins-maven-deploy-plugin-3.1.1
Bump maven-deploy-plugin from 3.0.0-M1 to 3.1.1
2023-05-25 14:53:56 +02:00
Harald Kuhr d38af3cb16 Merge pull request #761 from haraldk/dependabot/maven/org.apache.maven.plugins-maven-gpg-plugin-3.1.0
Bump maven-gpg-plugin from 1.6 to 3.1.0
2023-05-25 14:53:41 +02:00
Harald Kuhr c57e8f80fa Merge pull request #763 from haraldk/dependabot/maven/org.apache.maven.plugins-maven-shade-plugin-3.4.1
Bump maven-shade-plugin from 3.2.2 to 3.4.1
2023-05-25 14:39:24 +02:00
Harald Kuhr 4750359ada Merge pull request #766 from haraldk/dependabot/maven/org.apache.maven.plugins-maven-javadoc-plugin-3.5.0
Bump maven-javadoc-plugin from 3.2.0 to 3.5.0
2023-05-25 14:35:45 +02:00
Harald Kuhr cbe8038619 Merge pull request #767 from haraldk/dependabot/maven/org.apache.maven.plugins-maven-jar-plugin-3.3.0
Bump maven-jar-plugin from 2.4 to 3.3.0
2023-05-25 14:33:30 +02:00
Harald Kuhr 2d8125e69c Manual mockito bump 2023-05-25 14:29:32 +02:00
Harald Kuhr 57a664c093 Merge pull request #764 from haraldk/dependabot/maven/commons-io-commons-io-2.12.0
Bump commons-io from 2.11.0 to 2.12.0
2023-05-25 14:00:06 +02:00
Harald Kuhr 7f82377fd7 Merge pull request #762 from haraldk/dependabot/maven/javax.servlet-servlet-api-2.5
Bump servlet-api from 2.4 to 2.5
2023-05-25 13:59:05 +02:00
dependabot[bot] 72b9f19a51 Bump nexus-staging-maven-plugin from 1.6.8 to 1.6.13
Bumps nexus-staging-maven-plugin from 1.6.8 to 1.6.13.

---
updated-dependencies:
- dependency-name: org.sonatype.plugins:nexus-staging-maven-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-25 11:55:57 +00:00
dependabot[bot] 0083b8e77e Bump maven-scm-provider-gitexe from 1.11.2 to 2.0.1
Bumps maven-scm-provider-gitexe from 1.11.2 to 2.0.1.

---
updated-dependencies:
- dependency-name: org.apache.maven.scm:maven-scm-provider-gitexe
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-25 11:55:55 +00:00
dependabot[bot] 79982cd493 Bump maven-jar-plugin from 2.4 to 3.3.0
Bumps [maven-jar-plugin](https://github.com/apache/maven-jar-plugin) from 2.4 to 3.3.0.
- [Release notes](https://github.com/apache/maven-jar-plugin/releases)
- [Commits](https://github.com/apache/maven-jar-plugin/compare/maven-jar-plugin-2.4...maven-jar-plugin-3.3.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-jar-plugin
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-25 11:55:46 +00:00
dependabot[bot] f0db338f3b Bump maven-javadoc-plugin from 3.2.0 to 3.5.0
Bumps [maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.2.0 to 3.5.0.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.2.0...maven-javadoc-plugin-3.5.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-25 11:55:41 +00:00
Harald Kuhr 9db4e0b3ed More Dependabot PRs, please 2023-05-25 13:55:14 +02:00
Harald Kuhr cd4cbdcb82 Merge pull request #760 from haraldk/dependabot/github_actions/dot-github/workflows/mikepenz/action-junit-report-3.7.7
Bump mikepenz/action-junit-report from 3.7.6 to 3.7.7 in /.github/workflows
2023-05-25 13:45:06 +02:00
dependabot[bot] 15dc4b3852 Bump maven-deploy-plugin from 3.0.0-M1 to 3.1.1
Bumps [maven-deploy-plugin](https://github.com/apache/maven-deploy-plugin) from 3.0.0-M1 to 3.1.1.
- [Release notes](https://github.com/apache/maven-deploy-plugin/releases)
- [Commits](https://github.com/apache/maven-deploy-plugin/compare/maven-deploy-plugin-3.0.0-M1...maven-deploy-plugin-3.1.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-deploy-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-25 11:43:04 +00:00
dependabot[bot] a3534ecd59 Bump commons-io from 2.11.0 to 2.12.0
Bumps commons-io from 2.11.0 to 2.12.0.

---
updated-dependencies:
- dependency-name: commons-io:commons-io
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-25 11:43:00 +00:00
dependabot[bot] 7bb5fee23b Bump maven-shade-plugin from 3.2.2 to 3.4.1
Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.2.2 to 3.4.1.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.2.2...maven-shade-plugin-3.4.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-25 11:42:57 +00:00
dependabot[bot] 6cb7424bd0 Bump servlet-api from 2.4 to 2.5
Bumps servlet-api from 2.4 to 2.5.

---
updated-dependencies:
- dependency-name: javax.servlet:servlet-api
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-25 11:42:53 +00:00
dependabot[bot] 9aa04d311e Bump maven-gpg-plugin from 1.6 to 3.1.0
Bumps [maven-gpg-plugin](https://github.com/apache/maven-gpg-plugin) from 1.6 to 3.1.0.
- [Commits](https://github.com/apache/maven-gpg-plugin/compare/maven-gpg-plugin-1.6...maven-gpg-plugin-3.1.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-gpg-plugin
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-25 11:42:51 +00:00
dependabot[bot] 967e71dc92 Bump mikepenz/action-junit-report in /.github/workflows
Bumps [mikepenz/action-junit-report](https://github.com/mikepenz/action-junit-report) from 3.7.6 to 3.7.7.
- [Release notes](https://github.com/mikepenz/action-junit-report/releases)
- [Commits](https://github.com/mikepenz/action-junit-report/compare/959aefb7f095e717eb407fe917238d61ca323ff3...c0e4b81aaa0067314a2d0d06e19b512c9d8af4f5)

---
updated-dependencies:
- dependency-name: mikepenz/action-junit-report
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-25 11:42:47 +00:00
Harald Kuhr 628523ddc8 Dependabot workflow updates 2023-05-25 13:42:21 +02:00
Harald Kuhr 783c28ae0e More lenient test, using dynamic local port. 2023-05-25 12:16:38 +02:00
Harald Kuhr d35d67651f Merge pull request #759 from haraldk/dependabot/maven/org.apache.maven.plugins-maven-resources-plugin-3.3.1
Bump maven-resources-plugin from 3.2.0 to 3.3.1
2023-05-25 12:15:21 +02:00
Harald Kuhr 816d48efef Merge pull request #758 from haraldk/dependabot/maven/org.apache.maven.plugins-maven-pmd-plugin-3.21.0
Bump maven-pmd-plugin from 3.14.0 to 3.21.0
2023-05-25 12:15:07 +02:00
Harald Kuhr 25ee21d090 Merge pull request #757 from haraldk/dependabot/maven/junit-junit-4.13.2
Bump junit from 4.13.1 to 4.13.2
2023-05-25 12:02:51 +02:00
Harald Kuhr 536ea7ba88 Merge pull request #756 from haraldk/dependabot/maven/org.apache.maven.plugins-maven-checkstyle-plugin-3.3.0
Bump maven-checkstyle-plugin from 3.1.2 to 3.3.0
2023-05-25 12:02:36 +02:00
Harald Kuhr d2687383f5 Merge pull request #755 from haraldk/dependabot/maven/org.apache.maven.plugins-maven-help-plugin-3.4.0
Bump maven-help-plugin from 3.2.0 to 3.4.0
2023-05-25 11:39:05 +02:00
dependabot[bot] 3ce35e059c Bump maven-resources-plugin from 3.2.0 to 3.3.1
Bumps [maven-resources-plugin](https://github.com/apache/maven-resources-plugin) from 3.2.0 to 3.3.1.
- [Release notes](https://github.com/apache/maven-resources-plugin/releases)
- [Commits](https://github.com/apache/maven-resources-plugin/compare/maven-resources-plugin-3.2.0...maven-resources-plugin-3.3.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-resources-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-25 09:08:40 +00:00
dependabot[bot] 1d5359dd35 Bump maven-pmd-plugin from 3.14.0 to 3.21.0
Bumps [maven-pmd-plugin](https://github.com/apache/maven-pmd-plugin) from 3.14.0 to 3.21.0.
- [Release notes](https://github.com/apache/maven-pmd-plugin/releases)
- [Commits](https://github.com/apache/maven-pmd-plugin/compare/maven-pmd-plugin-3.14.0...maven-pmd-plugin-3.21.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-pmd-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-25 09:08:34 +00:00
dependabot[bot] 2699b75b79 Bump junit from 4.13.1 to 4.13.2
Bumps [junit](https://github.com/junit-team/junit4) from 4.13.1 to 4.13.2.
- [Release notes](https://github.com/junit-team/junit4/releases)
- [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.13.1.md)
- [Commits](https://github.com/junit-team/junit4/compare/r4.13.1...r4.13.2)

---
updated-dependencies:
- dependency-name: junit:junit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-25 09:08:30 +00:00
dependabot[bot] 4e614dfc7e Bump maven-checkstyle-plugin from 3.1.2 to 3.3.0
Bumps [maven-checkstyle-plugin](https://github.com/apache/maven-checkstyle-plugin) from 3.1.2 to 3.3.0.
- [Commits](https://github.com/apache/maven-checkstyle-plugin/compare/maven-checkstyle-plugin-3.1.2...maven-checkstyle-plugin-3.3.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-checkstyle-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-25 09:08:23 +00:00
dependabot[bot] 3a2efd9491 Bump maven-help-plugin from 3.2.0 to 3.4.0
Bumps [maven-help-plugin](https://github.com/apache/maven-help-plugin) from 3.2.0 to 3.4.0.
- [Commits](https://github.com/apache/maven-help-plugin/compare/maven-help-plugin-3.2.0...maven-help-plugin-3.4.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-help-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-25 09:08:18 +00:00
Harald Kuhr c5dc2e4e53 Update README.md 2023-05-25 10:29:09 +02:00
Harald Kuhr 41460bd32a JDK 20 compliance 2023-05-24 21:43:33 +02:00
Harald Kuhr 13b37b3839 Use Maven in batch mode! 2023-05-24 20:34:21 +02:00
Harald Kuhr 6dd74070f4 Remove transfer progress from Maven deploy output 2023-05-24 20:27:26 +02:00
Harald Kuhr 81b358b377 Attempt to fix problem with upgraded maven source plugin, take 2 2023-05-24 20:14:28 +02:00
Harald Kuhr 9715f4e74c Attempt to fix problem with upgraded maven source plugin. 2023-05-24 20:04:16 +02:00
Harald Kuhr 38256c8be0 Merge pull request #754 from haraldk/dependabot/maven/org.apache.maven.plugins-maven-surefire-report-plugin-3.1.0
Bump maven-surefire-report-plugin from 3.0.0-M5 to 3.1.0
2023-05-24 19:21:44 +02:00
Harald Kuhr bf3c1fad17 Merge pull request #753 from haraldk/dependabot/maven/org.apache.maven.plugins-maven-release-plugin-3.0.0
Bump maven-release-plugin from 3.0.0-M4 to 3.0.0
2023-05-24 19:21:16 +02:00
Harald Kuhr b8488ae39b Merge pull request #751 from haraldk/dependabot/maven/org.apache.maven.plugins-maven-source-plugin-3.3.0
Bump maven-source-plugin from 3.2.1 to 3.3.0
2023-05-24 19:19:54 +02:00
Harald Kuhr d3bea0ae38 Merge pull request #752 from haraldk/dependabot/maven/org.apache.maven.plugins-maven-compiler-plugin-3.11.0
Bump maven-compiler-plugin from 3.8.1 to 3.11.0
2023-05-24 19:19:15 +02:00
Harald Kuhr 9435410b1e Merge pull request #750 from haraldk/dependabot/maven/org.apache.maven.plugins-maven-surefire-plugin-3.1.0
Bump maven-surefire-plugin from 3.0.0-M5 to 3.1.0
2023-05-24 19:18:44 +02:00
Harald Kuhr f74e8c8ba1 Stop dependabot causing double workflow runs. 2023-05-24 18:48:32 +02:00
dependabot[bot] 0ae2c2f01d Bump maven-surefire-report-plugin from 3.0.0-M5 to 3.1.0
Bumps [maven-surefire-report-plugin](https://github.com/apache/maven-surefire) from 3.0.0-M5 to 3.1.0.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.0.0-M5...surefire-3.1.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-surefire-report-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-24 16:23:01 +00:00
dependabot[bot] 77c81a06bc Bump maven-release-plugin from 3.0.0-M4 to 3.0.0
Bumps [maven-release-plugin](https://github.com/apache/maven-release) from 3.0.0-M4 to 3.0.0.
- [Release notes](https://github.com/apache/maven-release/releases)
- [Commits](https://github.com/apache/maven-release/compare/maven-release-3.0.0-M4...maven-release-3.0.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-release-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-24 16:22:56 +00:00
dependabot[bot] 2bbcd88798 Bump maven-compiler-plugin from 3.8.1 to 3.11.0
Bumps [maven-compiler-plugin](https://github.com/apache/maven-compiler-plugin) from 3.8.1 to 3.11.0.
- [Release notes](https://github.com/apache/maven-compiler-plugin/releases)
- [Commits](https://github.com/apache/maven-compiler-plugin/compare/maven-compiler-plugin-3.8.1...maven-compiler-plugin-3.11.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-compiler-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-24 16:22:53 +00:00
dependabot[bot] 829fbe7547 Bump maven-source-plugin from 3.2.1 to 3.3.0
Bumps [maven-source-plugin](https://github.com/apache/maven-source-plugin) from 3.2.1 to 3.3.0.
- [Commits](https://github.com/apache/maven-source-plugin/compare/maven-source-plugin-3.2.1...maven-source-plugin-3.3.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-source-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-24 16:22:49 +00:00
dependabot[bot] 078425eed9 Bump maven-surefire-plugin from 3.0.0-M5 to 3.1.0
Bumps [maven-surefire-plugin](https://github.com/apache/maven-surefire) from 3.0.0-M5 to 3.1.0.
- [Release notes](https://github.com/apache/maven-surefire/releases)
- [Commits](https://github.com/apache/maven-surefire/compare/surefire-3.0.0-M5...surefire-3.1.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-surefire-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-24 16:22:44 +00:00
Harald Kuhr 8ddcbbd2b2 Create dependabot.yml 2023-05-24 18:22:20 +02:00
Harald Kuhr 507cca5fd7 Merge pull request #749 from joycebrum/master
Hash pin ci.yml
2023-05-24 18:12:15 +02:00
Joyce a4caac0c82 Hash pin ci.yml 2023-05-22 17:46:55 -03:00
Harald Kuhr 54c07b849c Added logo to README.md 2023-04-17 20:11:16 +02:00
Harald Kuhr c531d4f5d3 Reverted test, glossed over flakyness in library instead. 2023-04-04 16:30:45 +02:00
Harald Kuhr aa2e8e5d7e Fix flaky old test. 2023-04-04 16:06:42 +02:00
Harald Kuhr 76a35331b0 #744 TIFF: Re-complicated TIFF writing for the sake of performance... 2023-04-04 15:41:42 +02:00
Harald Kuhr 6b3f1c6ee3 #740 TIFF: Floating point predictor support. 2023-03-24 08:54:31 +01:00
Harald Kuhr c731e10e8f Merge pull request #742 from joycebrum/master
Create a Security Policy
2023-03-21 20:29:00 +01:00
Joyce 4a8c3530f7 Update SECURITY.md 2023-03-21 10:10:34 -03:00
Joyce e8996daa12 Update SECURITY.md to best effort 2023-03-21 10:03:27 -03:00
Joyce 9196e60c74 Create SECURITY.md 2023-03-20 14:49:44 -03:00
Harald Kuhr eabb8fd02b WebP cleanup. 2023-03-18 11:40:47 +01:00
Harald Kuhr 1794e336de WebP minor bugfix and optimization. 2023-03-18 11:34:24 +01:00
Harald Kuhr ac7612b3df WebP cleanup 2023-03-18 11:33:29 +01:00
Harald Kuhr 606fd53823 #738 PSD: No longer decompress PackBits across boundaries 2023-03-18 10:33:34 +01:00
Harald Kuhr 614a07e040 Merge pull request #737 from tc-wleite/WebP_FixAlphaSubsampling
WebP: Fix alpha decoding when source subsampling is used
2023-03-16 11:59:27 +01:00
tc-wleite 34e8d88007 Avoid creating another temporary raster, filtering on the tempRaster. 2023-03-15 17:23:53 -03:00
tc-wleite 9b727df901 Remove the TODO comment. 2023-03-15 16:56:46 -03:00
tc-wleite f1f98bb4a4 Use a static import. 2023-03-15 16:56:08 -03:00
tc-wleite b34b26e08c Let copyIntoRasterWithParams() handle null param. 2023-03-15 16:53:27 -03:00
Wladimir Leite 993e07ee34 Accept and handle null param in copyIntoRasterWithParams().
Co-authored-by: Harald Kuhr <harald.kuhr@gmail.com>
2023-03-15 16:47:53 -03:00
tc-wleite a377712bdb Replace the WebP to test alpha subsampling by a slightly smaller image. 2023-03-15 16:39:50 -03:00
tc-wleite e5dc6aa878 Add the new image to the basic reading test. 2023-03-15 11:44:35 -03:00
tc-wleite 46b1c1cf96 Test if a WebP with alpha was read correctly using subsampling. 2023-03-15 11:43:51 -03:00
tc-wleite d9300b1c90 Add to resources a test WebP with alpha and filters. 2023-03-15 11:39:10 -03:00
tc-wleite 0a2efb9eac Param can be null in readAlpha(). Copy alphaRaster to dst in this case. 2023-03-15 11:15:17 -03:00
tc-wleite 3eabc591d8 Fix: use raster instead of decodedRaster to keep previous behavior. 2023-03-15 09:39:10 -03:00
tc-wleite 5cefce2dbf Minor fix in code formatting. 2023-03-14 21:21:28 -03:00
tc-wleite 4c645c0220 Fix TODO comment message. 2023-03-14 21:04:59 -03:00
tc-wleite 703848ca45 Decode alpha using source dimensions and copy to destination later. 2023-03-14 21:01:29 -03:00
tc-wleite 0ebd18fcb6 Move to a static method the code that copies into a raster with params. 2023-03-14 20:59:54 -03:00
Harald Kuhr 29f7547a99 CI: Suppress download progress messages 2023-03-09 13:05:32 +01:00
Harald Kuhr 25cd351eee Servlet: Now logs a message on context startup to aid debugging.
+ bonus generic refactorings
2023-03-09 12:17:20 +01:00
Harald Kuhr 77c98c917e #733: Stricter permissions 2023-03-01 09:54:36 +01:00
Harald Kuhr 4bbe946f46 Merge pull request #731 from daaaaa/master
PSD: Add missing guide info in metadata
2023-02-01 10:17:39 +01:00
Davide Tantillo 78832ed923 PSD: Add missing guide info in metadata 2023-01-31 23:49:44 +01:00
Harald Kuhr 164cc11592 New versions, FAQ additions ++ 2022-11-23 15:41:57 +01:00
Harald Kuhr 8f5c1b409f #712 Core: Fix possible OOM situation in new stream implementation 2022-11-21 16:15:21 +01:00
Harald Kuhr 26981513d8 #714 PNM: Add support for writing TYPE_INT_* images + implementation of WriterSpi.canEncode 2022-11-21 16:13:54 +01:00
Harald Kuhr a3a30d54d4 Merge pull request #715 from KoenDG/batik_new
Batik upgraded to 1.16
2022-11-15 13:39:31 +01:00
Koen De Groote 102e9cff51 Batik upgraded to 1.16 2022-11-14 17:27:32 +01:00
Harald Kuhr da800be8c8 #713 PSD: Broken uncompressed reading from stream w/unknown length 2022-11-10 16:11:45 +01:00
Harald Kuhr 70493bd323 Merge pull request #710 from haraldk/snyk-fix-1db7a7baf4764ce7cab80fb2bc152b73
[Snyk] Fix for 2 vulnerabilities
2022-11-01 11:59:49 +01:00
snyk-bot 304d050bc3 fix: imageio/imageio-batik/pom.xml to reduce vulnerabilities
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JAVA-ORGAPACHEXMLGRAPHICS-3063442
- https://snyk.io/vuln/SNYK-JAVA-ORGAPACHEXMLGRAPHICS-3063691
2022-10-27 04:06:55 +00:00
Harald Kuhr 0443172666 #708 PSD: No longer emit warning for '8B64' (64 bit/long) resources. 2022-10-20 17:06:52 +02:00
Harald Kuhr cee2663f06 #707 WebP: Fix Alpha support the correct way... 2022-10-20 16:09:02 +02:00
Harald Kuhr 8f44cfc43c #707 WebP: Fix Alpha support 2022-10-20 16:00:12 +02:00
Harald Kuhr 8a240aac68 #704 Fix LSBBitReader to avoid back/forth seeking that invalidates buffer 2022-10-20 13:57:11 +02:00
Harald Kuhr 61424f33b6 #704 Tiny performance improvement + code clean-up 2022-10-19 20:46:24 +02:00
Harald Kuhr c7b9b1fadd Code clean-up. 2022-10-19 20:45:41 +02:00
Harald Kuhr ab08ec1e0d #705 No longer closes streams we didn't open 2022-10-18 20:25:31 +02:00
Harald Kuhr cbe78dc67f ...and removed System.out.. Ouch... 2022-10-18 16:08:03 +02:00
Harald Kuhr c9e11f171f Fixed typo... 2022-10-18 16:05:54 +02:00
Harald Kuhr bc2c0c2301 [maven-release-plugin] prepare for next development iteration 2022-10-15 12:12:53 +02:00
143 changed files with 3346 additions and 1318 deletions
+13
View File
@@ -0,0 +1,13 @@
version: 2
updates:
# Maven/Java library updates
- package-ecosystem: "maven"
directory: "/"
schedule:
interval: "daily"
open-pull-requests-limit: 10
# GitHub actions updates
- package-ecosystem: "github-actions"
directory: "/.github/workflows"
schedule:
interval: "daily"
+26 -14
View File
@@ -1,6 +1,14 @@
name: CI name: CI
on: [ push, pull_request ] on:
push:
branches:
- '**'
- '!dependabot/**'
pull_request:
branches: [ 'master' ]
permissions: read-all
jobs: jobs:
test: test:
@@ -9,20 +17,22 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ ubuntu-latest, windows-latest, macos-latest ] os: [ ubuntu-latest, windows-latest, macos-latest ]
java: [ 8, 11, 17, 18 ] java: [ 8, 11, 17, 21 ]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
permissions:
checks: write
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: actions/setup-java@v3 - uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: ${{ matrix.java }} java-version: ${{ matrix.java }}
java-package: jdk java-package: jdk
cache: 'maven' cache: 'maven'
- name: Run Tests - name: Run Tests
run: mvn test run: mvn --batch-mode --no-transfer-progress test
- name: Publish Test Report - name: Publish Test Report
uses: mikepenz/action-junit-report@v3 uses: mikepenz/action-junit-report@0831a82caad2465c31c6dd929978f640cb42556c # v4.0.3
if: ${{ !cancelled() }} if: ${{ !cancelled() }}
with: with:
report_paths: "**/target/surefire-reports/TEST*.xml" report_paths: "**/target/surefire-reports/TEST*.xml"
@@ -31,15 +41,17 @@ jobs:
test_oracle: test_oracle:
name: Test Oracle JDK 8 with KCMS=${{ matrix.kcms }} name: Test Oracle JDK 8 with KCMS=${{ matrix.kcms }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
checks: write
strategy: strategy:
matrix: matrix:
kcms: [ true, false ] kcms: [ true, false ]
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- run: | - run: |
download_url="https://javadl.oracle.com/webapps/download/AutoDL?BundleId=245038_d3c52aa6bfa54d3ca74e617f18309292" download_url="https://javadl.oracle.com/webapps/download/AutoDL?BundleId=245038_d3c52aa6bfa54d3ca74e617f18309292"
wget -O $RUNNER_TEMP/java_package.tar.gz $download_url wget -O $RUNNER_TEMP/java_package.tar.gz $download_url
- uses: actions/setup-java@v3 - uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0
with: with:
distribution: 'jdkfile' distribution: 'jdkfile'
jdkFile: ${{ runner.temp }}/java_package.tar.gz jdkFile: ${{ runner.temp }}/java_package.tar.gz
@@ -52,9 +64,9 @@ jobs:
- name: Display Java version - name: Display Java version
run: java -version run: java -version
- name: Run Tests - name: Run Tests
run: mvn test run: mvn --batch-mode --no-transfer-progress test
- name: Publish Test Report - name: Publish Test Report
uses: mikepenz/action-junit-report@v3 uses: mikepenz/action-junit-report@0831a82caad2465c31c6dd929978f640cb42556c # v4.0.3
if: ${{ !cancelled() }} if: ${{ !cancelled() }}
with: with:
report_paths: "**/target/surefire-reports/TEST*.xml" report_paths: "**/target/surefire-reports/TEST*.xml"
@@ -66,9 +78,9 @@ jobs:
if: github.ref == 'refs/heads/master' # only perform on latest master if: github.ref == 'refs/heads/master' # only perform on latest master
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Set up Maven Central - name: Set up Maven Central
uses: actions/setup-java@v3 uses: actions/setup-java@0ab4596768b603586c0de567f2430c30f5b0d2b0 # v3.13.0
with: # running setup-java again overwrites the settings.xml with: # running setup-java again overwrites the settings.xml
distribution: 'temurin' distribution: 'temurin'
java-version: '8' java-version: '8'
@@ -80,10 +92,10 @@ jobs:
gpg-passphrase: MAVEN_CENTRAL_GPG_PASSPHRASE # env variable for GPG private key passphrase (3) gpg-passphrase: MAVEN_CENTRAL_GPG_PASSPHRASE # env variable for GPG private key passphrase (3)
- name: Get Project Version - name: Get Project Version
run: | run: |
echo "PROJECT_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)" >> $GITHUB_ENV echo "PROJECT_VERSION=$(mvn --batch-mode help:evaluate -Dexpression=project.version -q -DforceStdout)" >> $GITHUB_ENV
- name: Publish to Maven Central - name: Publish to Maven Central
if: ${{ endsWith(env.PROJECT_VERSION, '-SNAPSHOT') }} if: ${{ endsWith(env.PROJECT_VERSION, '-SNAPSHOT') }}
run: mvn deploy -P release -DskipTests run: mvn --batch-mode --no-transfer-progress deploy -P release -DskipTests
env: env:
MAVEN_CENTRAL_USERNAME: ${{ secrets.SONATYPE_USERNAME }} # must be the same env variable name as (1) MAVEN_CENTRAL_USERNAME: ${{ secrets.SONATYPE_USERNAME }} # must be the same env variable name as (1)
MAVEN_CENTRAL_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} # must be the same env variable name as (2) MAVEN_CENTRAL_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} # must be the same env variable name as (2)
+69
View File
@@ -0,0 +1,69 @@
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@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@74483a38d39275f33fcff5f35b679b5ca4a26a99 # v2.22.5
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@74483a38d39275f33fcff5f35b679b5ca4a26a99 # v2.22.5
# ℹ️ 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@74483a38d39275f33fcff5f35b679b5ca4a26a99 # v2.22.5
with:
category: "/language:${{matrix.language}}"
+62
View File
@@ -0,0 +1,62 @@
# 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@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
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@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
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@74483a38d39275f33fcff5f35b679b5ca4a26a99 # v2.22.5
with:
sarif_file: results.sarif
+1
View File
@@ -15,3 +15,4 @@ private
profiles.xml profiles.xml
Thumbs.db Thumbs.db
.DS_Store .DS_Store
/.metadata/
+63 -73
View File
@@ -1,9 +1,15 @@
[![CI](https://github.com/haraldk/TwelveMonkeys/actions/workflows/ci.yml/badge.svg)](https://github.com/haraldk/TwelveMonkeys/actions/workflows/ci.yml) [![CI](https://github.com/haraldk/TwelveMonkeys/actions/workflows/ci.yml/badge.svg)](https://github.com/haraldk/TwelveMonkeys/actions/workflows/ci.yml)
[![CodeQL](https://github.com/haraldk/TwelveMonkeys/actions/workflows/codeql.yml/badge.svg)](https://github.com/haraldk/TwelveMonkeys/actions/workflows/codeql.yml)
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/haraldk/TwelveMonkeys/badge)](https://securityscorecards.dev/viewer/?uri=github.com/haraldk/TwelveMonkeys)
[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/7900/badge)](https://www.bestpractices.dev/projects/7900)
[![Maven Central](https://img.shields.io/maven-central/v/com.twelvemonkeys.imageio/imageio?color=slateblue)](https://search.maven.org/search?q=g:com.twelvemonkeys.imageio) [![Maven Central](https://img.shields.io/maven-central/v/com.twelvemonkeys.imageio/imageio?color=slateblue)](https://search.maven.org/search?q=g:com.twelvemonkeys.imageio)
[![Maven Snapshot](https://img.shields.io/nexus/s/com.twelvemonkeys.imageio/imageio?label=development&server=https%3A%2F%2Foss.sonatype.org&color=slateblue)](https://oss.sonatype.org/content/repositories/snapshots/com/twelvemonkeys/) [![Maven Snapshot](https://img.shields.io/nexus/s/com.twelvemonkeys.imageio/imageio?label=development&server=https%3A%2F%2Foss.sonatype.org&color=slateblue)](https://oss.sonatype.org/content/repositories/snapshots/com/twelvemonkeys/)
[![StackOverflow](https://img.shields.io/badge/stack_overflow-twelvemonkeys-orange.svg)](https://stackoverflow.com/questions/tagged/twelvemonkeys) [![StackOverflow](https://img.shields.io/badge/stack_overflow-twelvemonkeys-orange.svg)](https://stackoverflow.com/questions/tagged/twelvemonkeys)
[![Donate](https://img.shields.io/badge/donate-PayPal-blue.svg)](https://paypal.me/haraldk76/100) [![Donate](https://img.shields.io/badge/donate-PayPal-blue.svg)](https://paypal.me/haraldk76/100)
![Logo](logo.png)
## About ## About
TwelveMonkeys ImageIO provides extended image file format support for the Java platform, through plugins for the `javax.imageio.*` package. TwelveMonkeys ImageIO provides extended image file format support for the Java platform, through plugins for the `javax.imageio.*` package.
@@ -272,12 +278,12 @@ To depend on the JPEG and TIFF plugin using Maven, add the following to your POM
<dependency> <dependency>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-jpeg</artifactId> <artifactId>imageio-jpeg</artifactId>
<version>3.8.1</version> <version>3.9.4</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-tiff</artifactId> <artifactId>imageio-tiff</artifactId>
<version>3.8.1</version> <version>3.9.4</version>
</dependency> </dependency>
<!-- <!--
@@ -287,7 +293,7 @@ To depend on the JPEG and TIFF plugin using Maven, add the following to your POM
<dependency> <dependency>
<groupId>com.twelvemonkeys.servlet</groupId> <groupId>com.twelvemonkeys.servlet</groupId>
<artifactId>servlet</artifactId> <artifactId>servlet</artifactId>
<version>3.8.1</version> <version>3.9.4</version>
</dependency> </dependency>
<!-- <!--
@@ -296,7 +302,7 @@ To depend on the JPEG and TIFF plugin using Maven, add the following to your POM
<dependency> <dependency>
<groupId>com.twelvemonkeys.servlet</groupId> <groupId>com.twelvemonkeys.servlet</groupId>
<artifactId>servlet</artifactId> <artifactId>servlet</artifactId>
<version>3.8.1</version> <version>3.9.4</version>
<classifier>jakarta</classifier> <classifier>jakarta</classifier>
</dependency> </dependency>
</dependencies> </dependencies>
@@ -306,13 +312,13 @@ To depend on the JPEG and TIFF plugin using Maven, add the following to your POM
To depend on the JPEG and TIFF plugin in your IDE or program, add all of the following JARs to your class path: To depend on the JPEG and TIFF plugin in your IDE or program, add all of the following JARs to your class path:
twelvemonkeys-common-lang-3.8.1.jar twelvemonkeys-common-lang-3.9.4.jar
twelvemonkeys-common-io-3.8.1.jar twelvemonkeys-common-io-3.9.4.jar
twelvemonkeys-common-image-3.8.1.jar twelvemonkeys-common-image-3.9.4.jar
twelvemonkeys-imageio-core-3.8.1.jar twelvemonkeys-imageio-core-3.9.4.jar
twelvemonkeys-imageio-metadata-3.8.1.jar twelvemonkeys-imageio-metadata-3.9.4.jar
twelvemonkeys-imageio-jpeg-3.8.1.jar twelvemonkeys-imageio-jpeg-3.9.4.jar
twelvemonkeys-imageio-tiff-3.8.1.jar twelvemonkeys-imageio-tiff-3.9.4.jar
#### Deploying the plugins in a web app #### Deploying the plugins in a web app
@@ -378,81 +384,50 @@ Other "fat" JAR bundlers will probably have similar mechanisms to merge entries
### Links to prebuilt binaries ### Links to prebuilt binaries
##### Latest version (3.8.1) ##### Latest version (3.9.4)
Requires Java 7 or later. The latest version that will run on Java 7 is 3.9.4. Later versions will require Java 8 or later.
Common dependencies Common dependencies
* [common-lang-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-lang/3.8.1/common-lang-3.8.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.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-io/3.8.1/common-io-3.8.1.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.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-image/3.8.1/common-image-3.8.1.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 dependencies
* [imageio-core-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-core/3.8.1/imageio-core-3.8.1.jar) * [imageio-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.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-metadata/3.8.1/imageio-metadata-3.8.1.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 plugins
* [imageio-bmp-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-bmp/3.8.1/imageio-bmp-3.8.1.jar) * [imageio-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.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-hdr/3.8.1/imageio-hdr-3.8.1.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.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-icns/3.8.1/imageio-icns-3.8.1.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.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-iff/3.8.1/imageio-iff-3.8.1.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.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jpeg/3.8.1/imageio-jpeg-3.8.1.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.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pcx/3.8.1/imageio-pcx-3.8.1.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.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pict/3.8.1/imageio-pict-3.8.1.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.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pnm/3.8.1/imageio-pnm-3.8.1.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.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-psd/3.8.1/imageio-psd-3.8.1.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.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-sgi/3.8.1/imageio-sgi-3.8.1.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.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tga/3.8.1/imageio-tga-3.8.1.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.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-thumbsdb/3.8.1/imageio-thumbsdb-3.8.1.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.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tiff/3.8.1/imageio-tiff-3.8.1.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.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-webp/3.8.1/imageio-webp-3.8.1.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.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-xwd/3.8.1/imageio-xwd-3.8.1.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 plugins requiring 3rd party libs
* [imageio-batik-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-batik/3.8.1/imageio-batik-3.8.1.jar) * [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 Photoshop Path support for ImageIO
* [imageio-clippath-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-clippath/3.8.1/imageio-clippath-3.8.1.jar) * [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 support
* [servlet-3.8.1.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/servlet/servlet/3.8.1/servlet-3.8.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)
##### Old version (3.0.x)
Use this version for projects that requires Java 6 or need the JMagick support. *Does not support Java 8 or later*.
Common dependencies
* [common-lang-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-lang/3.0.2/common-lang-3.0.2.jar)
* [common-io-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-io/3.0.2/common-io-3.0.2.jar)
* [common-image-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-image/3.0.2/common-image-3.0.2.jar)
ImageIO dependencies
* [imageio-core-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-core/3.0.2/imageio-core-3.0.2.jar)
* [imageio-metadata-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-metadata/3.0.2/imageio-metadata-3.0.2.jar)
ImageIO plugins
* [imageio-jpeg-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jpeg/3.0.2/imageio-jpeg-3.0.2.jar)
* [imageio-tiff-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tiff/3.0.2/imageio-tiff-3.0.2.jar)
* [imageio-psd-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-psd/3.0.2/imageio-psd-3.0.2.jar)
* [imageio-pict-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pict/3.0.2/imageio-pict-3.0.2.jar)
* [imageio-iff-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-iff/3.0.2/imageio-iff-3.0.2.jar)
* [imageio-icns-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-icns/3.0.2/imageio-icns-3.0.2.jar)
* [imageio-ico-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-ico/3.0.2/imageio-ico-3.0.2.jar)
* [imageio-thumbsdb-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-thumbsdb/3.0.2/imageio-thumbsdb-3.0.2.jar)
ImageIO plugins requiring 3rd party libs
* [imageio-batik-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-batik/3.0.2/imageio-batik-3.0.2.jar)
* [imageio-jmagick-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jmagick/3.0.2/imageio-jmagick-3.0.2.jar)
Servlet support
* [servlet-3.0.2.jar](https://search.maven.org/remotecontent?filepath=com/twelvemonkeys/servlet/servlet/3.0.2/servlet-3.0.2.jar)
## License ## License
This project is provided under the OSI approved [BSD license](https://opensource.org/licenses/BSD-3-Clause): This project is provided under the OSI approved [BSD license](https://opensource.org/licenses/BSD-3-Clause):
Copyright (c) 2008-2020, Harald Kuhr Copyright (c) 2008-2022, Harald Kuhr
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@@ -484,8 +459,9 @@ This project is provided under the OSI approved [BSD license](https://opensource
q: How do I use it? q: How do I use it?
a: The easiest way is to build your own project using Maven, and just add dependencies to the specific plug-ins you need. a: The easiest way is to build your own project using Maven, Gradle or other build tool with dependency management,
If you don't use Maven, make sure you have all the necessary JARs in classpath. See the Install section above. and just add dependencies to the specific plug-ins you need.
If you don't use such a build tool, make sure you have all the necessary JARs in classpath. See the Install section above.
q: What changes do I have to make to my code in order to use the plug-ins? q: What changes do I have to make to my code in order to use the plug-ins?
@@ -503,22 +479,36 @@ q: How does it work?
a: The TwelveMonkeys ImageIO project contains plug-ins for ImageIO. ImageIO uses a service lookup mechanism, to discover plug-ins at runtime. a: The TwelveMonkeys ImageIO project contains plug-ins for ImageIO. ImageIO uses a service lookup mechanism, to discover plug-ins at runtime.
All you have have to do, is to make sure you have the TwelveMonkeys JARs in your classpath. All you have to do, is to make sure you have the TwelveMonkeys ImageIO JARs in your classpath.
You can read more about the registry and the lookup mechanism in the [IIORegistry API doc](https://docs.oracle.com/javase/7/docs/api/javax/imageio/spi/IIORegistry.html). You can read more about the registry and the lookup mechanism in the [IIORegistry API doc](https://docs.oracle.com/javase/7/docs/api/javax/imageio/spi/IIORegistry.html).
The fine print: The TwelveMonkeys service providers for JPEG, BMP and TIFF, overrides the onRegistration method, and The fine print: The TwelveMonkeys service providers for JPEG, BMP and TIFF, overrides the onRegistration method, and
utilizes the pairwise partial ordering mechanism of the `IIOServiceRegistry` to make sure it is installed before utilizes the pairwise partial ordering mechanism of the `IIOServiceRegistry` to make sure it is installed before
the Sun/Oracle provided `JPEGImageReader` and `BMPImageReader`, and the Apple provided `TIFFImageReader` on OS X, the Sun/Oracle provided `JPEGImageReader`, `BMPImageReader` `TIFFImageReader`, and the Apple provided `TIFFImageReader` on OS X,
respectively. Using the pairwise ordering will not remove any functionality form these implementations, but in most respectively. Using the pairwise ordering will not remove any functionality form these implementations, but in most
cases you'll end up using the TwelveMonkeys plug-ins instead. cases you'll end up using the TwelveMonkeys plug-ins instead.
q: Why is there no support for common formats like GIF or PNG? q: Why is there no support for common formats like GIF or PNG?
a: The short answer is simply that the built-in support in ImageIO for these formats are good enough as-is. a: The short answer is simply that the built-in support in ImageIO for these formats are considered good enough as-is.
If you are looking for better PNG write performance on Java 7 and 8, see [JDK9 PNG Writer Backport](https://github.com/gredler/jdk9-png-writer-backport). If you are looking for better PNG write performance on Java 7 and 8, see [JDK9 PNG Writer Backport](https://github.com/gredler/jdk9-png-writer-backport).
q: When is the next release? What is the current release schedule?
a: The goal is to make monthly releases, containing bug fixes and minor new features.
And quarterly releases with more "major" features.
q: I love this project! How can I help?
a: Have a look at the open issues, and see if there are any issues you can help fix, or provide sample file or create test cases for.
It is also possible for you or your organization to become a sponsor, through GitHub Sponsors.
Providing funding will allow us to spend more time on fixing bugs and implementing new features.
q: What about JAI? Several of the formats are already supported by JAI. q: What about JAI? Several of the formats are already supported by JAI.
a: While JAI (and jai-imageio in particular) have support for some of the same formats, JAI has some major issues. a: While JAI (and jai-imageio in particular) have support for some of the same formats, JAI has some major issues.
+5
View File
@@ -0,0 +1,5 @@
# Security Policy
To report a security issue, please disclose it at [security advisory](https://github.com/haraldk/TwelveMonkeys/security/advisories/new).
Vulnerabilities will be disclosed in a best effort base.
+1 -1
View File
@@ -5,7 +5,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys</groupId> <groupId>com.twelvemonkeys</groupId>
<artifactId>twelvemonkeys</artifactId> <artifactId>twelvemonkeys</artifactId>
<version>3.9.0</version> <version>3.10.2-SNAPSHOT</version>
</parent> </parent>
<groupId>com.twelvemonkeys.bom</groupId> <groupId>com.twelvemonkeys.bom</groupId>
+11 -2
View File
@@ -4,13 +4,13 @@
<parent> <parent>
<groupId>com.twelvemonkeys.common</groupId> <groupId>com.twelvemonkeys.common</groupId>
<artifactId>common</artifactId> <artifactId>common</artifactId>
<version>3.9.0</version> <version>3.10.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>common-image</artifactId> <artifactId>common-image</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>TwelveMonkeys :: Common :: Image</name> <name>TwelveMonkeys :: Common :: Image</name>
<description> <description>
The TwelveMonkeys Common Image support TwelveMonkeys Common image support classes.
</description> </description>
<properties> <properties>
@@ -36,4 +36,13 @@
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
</plugin>
</plugins>
</build>
</project> </project>
@@ -79,7 +79,7 @@ public final class BufferedImageFactory {
private int scanSize; private int scanSize;
private ColorModel sourceColorModel; private ColorModel sourceColorModel;
private Hashtable sourceProperties; // ImageConsumer API dictates Hashtable private Hashtable<?, ?> sourceProperties; // ImageConsumer API dictates Hashtable
private Object sourcePixels; private Object sourcePixels;
@@ -91,21 +91,21 @@ public final class BufferedImageFactory {
/** /**
* Creates a {@code BufferedImageFactory}. * Creates a {@code BufferedImageFactory}.
* @param pSource the source image * @param source the source image
* @throws IllegalArgumentException if {@code pSource == null} * @throws IllegalArgumentException if {@code source == null}
*/ */
public BufferedImageFactory(final Image pSource) { public BufferedImageFactory(final Image source) {
this(pSource != null ? pSource.getSource() : null); this(source != null ? source.getSource() : null);
} }
/** /**
* Creates a {@code BufferedImageFactory}. * Creates a {@code BufferedImageFactory}.
* @param pSource the source image producer * @param source the source image producer
* @throws IllegalArgumentException if {@code pSource == null} * @throws IllegalArgumentException if {@code source == null}
*/ */
public BufferedImageFactory(final ImageProducer pSource) { public BufferedImageFactory(final ImageProducer source) {
Validate.notNull(pSource, "source"); Validate.notNull(source, "source");
producer = pSource; producer = source;
} }
/** /**
@@ -155,44 +155,44 @@ public final class BufferedImageFactory {
/** /**
* Sets the source region (AOI) for the new image. * Sets the source region (AOI) for the new image.
* *
* @param pRegion the source region * @param region the source region
*/ */
public void setSourceRegion(final Rectangle pRegion) { public void setSourceRegion(final Rectangle region) {
// Re-fetch everything, if region changed // Re-fetch everything, if region changed
if (x != pRegion.x || y != pRegion.y || width != pRegion.width || height != pRegion.height) { if (x != region.x || y != region.y || width != region.width || height != region.height) {
dispose(); dispose();
} }
x = pRegion.x; x = region.x;
y = pRegion.y; y = region.y;
width = pRegion.width; width = region.width;
height = pRegion.height; height = region.height;
} }
/** /**
* Sets the source subsampling for the new image. * Sets the source subsampling for the new image.
* *
* @param pXSub horizontal subsampling factor * @param xSubsampling horizontal subsampling factor
* @param pYSub vertical subsampling factor * @param ySubsampling vertical subsampling factor
*/ */
public void setSourceSubsampling(int pXSub, int pYSub) { public void setSourceSubsampling(int xSubsampling, int ySubsampling) {
// Re-fetch everything, if subsampling changed // Re-fetch everything, if subsampling changed
if (xSub != pXSub || ySub != pYSub) { if (xSub != xSubsampling || ySub != ySubsampling) {
dispose(); dispose();
} }
if (pXSub > 1) { if (xSubsampling > 1) {
xSub = pXSub; xSub = xSubsampling;
} }
if (pYSub > 1) { if (ySubsampling > 1) {
ySub = pYSub; ySub = ySubsampling;
} }
} }
private synchronized void doFetch(boolean pColorModelOnly) throws ImageConversionException { private synchronized void doFetch(final boolean colorModelOnly) throws ImageConversionException {
if (!fetching && (!pColorModelOnly && buffered == null || buffered == null && sourceColorModel == null)) { if (!fetching && (!colorModelOnly && buffered == null || buffered == null && sourceColorModel == null)) {
// NOTE: Subsampling is only applied if extracting full image // NOTE: Subsampling is only applied if extracting full image
if (!pColorModelOnly && (xSub > 1 || ySub > 1)) { if (!colorModelOnly && (xSub > 1 || ySub > 1)) {
// If only sampling a region, the region must be scaled too // If only sampling a region, the region must be scaled too
if (width > 0 && height > 0) { if (width > 0 && height > 0) {
width = (width + xSub - 1) / xSub; width = (width + xSub - 1) / xSub;
@@ -207,38 +207,41 @@ public final class BufferedImageFactory {
// Start fetching // Start fetching
fetching = true; fetching = true;
readColorModelOnly = pColorModelOnly; readColorModelOnly = colorModelOnly;
producer.startProduction(consumer); // Note: If single-thread (synchronous), this call will block producer.startProduction(consumer); // Note: If single-thread (synchronous), this call will block
// Wait until the producer wakes us up, by calling imageComplete // Wait until the producer wakes us up, by calling imageComplete
while (fetching) { while (fetching) {
try { try {
wait(200l); wait(200L);
} }
catch (InterruptedException e) { catch (InterruptedException e) {
throw new ImageConversionException("Image conversion aborted: " + e.getMessage(), e); throw new ImageConversionException("Image conversion aborted: " + e.getMessage(), e);
} }
} }
if (consumerException != null) { try {
throw new ImageConversionException("Image conversion failed: " + consumerException.getMessage(), consumerException); if (consumerException != null) {
} throw new ImageConversionException("Image conversion failed: " + consumerException.getMessage(), consumerException);
}
if (pColorModelOnly) { if (colorModelOnly) {
createColorModel(); createColorModel();
}
else {
createBuffered();
}
} }
else { finally {
createBuffered(); // Clean up, in case any objects are copied/cloned, so we can free resources
freeResources();
} }
} }
} }
private void createColorModel() { private void createColorModel() {
colorModel = sourceColorModel; colorModel = sourceColorModel;
// Clean up, in case any objects are copied/cloned, so we can free resources
freeResources();
} }
private void createBuffered() { private void createBuffered() {
@@ -253,8 +256,9 @@ public final class BufferedImageFactory {
} }
} }
// Clean up, in case any objects are copied/cloned, so we can free resources if (buffered == null) {
freeResources(); throw new ImageConversionException("Could not create BufferedImage");
}
} }
private void freeResources() { private void freeResources() {
@@ -280,27 +284,27 @@ public final class BufferedImageFactory {
/** /**
* Adds a progress listener to this factory. * Adds a progress listener to this factory.
* *
* @param pListener the progress listener * @param listener the progress listener
*/ */
public void addProgressListener(ProgressListener pListener) { public void addProgressListener(ProgressListener listener) {
if (pListener == null) { if (listener == null) {
return; return;
} }
if (listeners == null) { if (listeners == null) {
listeners = new CopyOnWriteArrayList<ProgressListener>(); listeners = new CopyOnWriteArrayList<>();
} }
listeners.add(pListener); listeners.add(listener);
} }
/** /**
* Removes a progress listener from this factory. * Removes a progress listener from this factory.
* *
* @param pListener the progress listener * @param listener the progress listener
*/ */
public void removeProgressListener(ProgressListener pListener) { public void removeProgressListener(ProgressListener listener) {
if (pListener == null) { if (listener == null) {
return; return;
} }
@@ -308,7 +312,7 @@ public final class BufferedImageFactory {
return; return;
} }
listeners.remove(pListener); listeners.remove(listener);
} }
/** /**
@@ -324,21 +328,22 @@ public final class BufferedImageFactory {
* Converts an array of {@code int} pixels to an array of {@code short} * Converts an array of {@code int} pixels to an array of {@code short}
* pixels. The conversion is done, by masking out the * pixels. The conversion is done, by masking out the
* <em>higher 16 bits</em> of the {@code int}. * <em>higher 16 bits</em> of the {@code int}.
* * <p>
* For any given {@code int}, the {@code short} value is computed as * For any given {@code int}, the {@code short} value is computed as
* follows: * follows:
* <blockquote>{@code * <blockquote>{@code
* short value = (short) (intValue & 0x0000ffff); * short value = (short) (intValue & 0x0000ffff);
* }</blockquote> * }</blockquote>
* </p>
* *
* @param pPixels the pixel data to convert * @param inputPixels the pixel data to convert
* @return an array of {@code short}s, same lenght as {@code pPixels} * @return an array of {@code short}s, same length as {@code inputPixels}
*/ */
private static short[] toShortPixels(int[] pPixels) { private static short[] toShortPixels(int[] inputPixels) {
short[] pixels = new short[pPixels.length]; short[] pixels = new short[inputPixels.length];
for (int i = 0; i < pixels.length; i++) { for (int i = 0; i < pixels.length; i++) {
pixels[i] = (short) (pPixels[i] & 0xffff); pixels[i] = (short) (inputPixels[i] & 0xffff);
} }
return pixels; return pixels;
@@ -351,17 +356,17 @@ public final class BufferedImageFactory {
* @see BufferedImageFactory#addProgressListener * @see BufferedImageFactory#addProgressListener
* @see BufferedImageFactory#removeProgressListener * @see BufferedImageFactory#removeProgressListener
*/ */
public static interface ProgressListener extends EventListener { public interface ProgressListener extends EventListener {
/** /**
* Reports progress to this listener. * Reports progress to this listener.
* Invoked by the {@code BufferedImageFactory} to report progress in * Invoked by the {@code BufferedImageFactory} to report progress in
* the image decoding. * the image decoding.
* *
* @param pFactory the factory reporting the progress * @param factory the factory reporting the progress
* @param pPercentage the percentage of progress * @param percentage the percentage of progress
*/ */
void progress(BufferedImageFactory pFactory, float pPercentage); void progress(BufferedImageFactory factory, float percentage);
} }
private class Consumer implements ImageConsumer { private class Consumer implements ImageConsumer {
@@ -446,18 +451,18 @@ public final class BufferedImageFactory {
processProgress(pY + pHeight); processProgress(pY + pHeight);
} }
public void setPixels(int pX, int pY, int pWidth, int pHeight, ColorModel pModel, short[] pPixels, int pOffset, int pScanSize) { public void setPixels(int x, int y, int width, int height, ColorModel colorModel, short[] pixels, int offset, int scanSize) {
setPixelsImpl(pX, pY, pWidth, pHeight, pModel, pPixels, pOffset, pScanSize); setPixelsImpl(x, y, width, height, colorModel, pixels, offset, scanSize);
} }
private void setColorModelOnce(final ColorModel pModel) { private void setColorModelOnce(final ColorModel colorModel) {
// NOTE: There seems to be a "bug" in AreaAveragingScaleFilter, as it // NOTE: There seems to be a "bug" in AreaAveragingScaleFilter, as it
// first passes the original color model through in setColorModel, then // first passes the original color model through in setColorModel, then
// later replaces it with the default RGB in the first setPixels call // later replaces it with the default RGB in the first setPixels call
// (this is probably allowed according to the spec, but it's a waste of time and space). // (this is probably allowed according to the spec, but it's a waste of time and space).
if (sourceColorModel != pModel) { if (sourceColorModel != colorModel) {
if (/*sourceColorModel == null ||*/ sourcePixels == null) { if (sourcePixels == null) {
sourceColorModel = pModel; sourceColorModel = colorModel;
} }
else { else {
throw new IllegalStateException("Change of ColorModel after pixel delivery not supported"); throw new IllegalStateException("Change of ColorModel after pixel delivery not supported");
@@ -470,17 +475,16 @@ public final class BufferedImageFactory {
} }
} }
public void imageComplete(int pStatus) { @Override
public void imageComplete(int status) {
fetching = false; fetching = false;
if (producer != null) { if (producer != null) {
producer.removeConsumer(this); producer.removeConsumer(this);
} }
switch (pStatus) { if (status == ImageConsumer.IMAGEERROR) {
case ImageConsumer.IMAGEERROR: consumerException = new ImageConversionException("ImageConsumer.IMAGEERROR");
consumerException = new ImageConversionException("ImageConsumer.IMAGEERROR");
break;
} }
synchronized (BufferedImageFactory.this) { synchronized (BufferedImageFactory.this) {
@@ -488,16 +492,18 @@ public final class BufferedImageFactory {
} }
} }
public void setColorModel(ColorModel pModel) { @Override
setColorModelOnce(pModel); public void setColorModel(ColorModel colorModel) {
setColorModelOnce(colorModel);
} }
public void setDimensions(int pWidth, int pHeight) { @Override
public void setDimensions(int w, int h) {
if (width < 0) { if (width < 0) {
width = pWidth - x; width = w - x;
} }
if (height < 0) { if (height < 0) {
height = pHeight - y; height = h - y;
} }
// Hmm.. Special case, but is it a good idea? // Hmm.. Special case, but is it a good idea?
@@ -506,27 +512,31 @@ public final class BufferedImageFactory {
} }
} }
public void setHints(int pHintflags) { @Override
public void setHints(int hintFlags) {
// ignore // ignore
} }
public void setPixels(int pX, int pY, int pWidth, int pHeight, ColorModel pModel, byte[] pPixels, int pOffset, int pScanSize) { @Override
setPixelsImpl(pX, pY, pWidth, pHeight, pModel, pPixels, pOffset, pScanSize); public void setPixels(int x, int y, int width, int height, ColorModel colorModel, byte[] pixels, int offset, int scanSize) {
setPixelsImpl(x, y, width, height, colorModel, pixels, offset, scanSize);
} }
public void setPixels(int pX, int pY, int pWeigth, int pHeight, ColorModel pModel, int[] pPixels, int pOffset, int pScanSize) { @Override
if (pModel.getTransferType() == DataBuffer.TYPE_USHORT) { public void setPixels(int x, int y, int width, int height, ColorModel colorModel, int[] pixels, int offset, int scanSize) {
if (colorModel.getTransferType() == DataBuffer.TYPE_USHORT) {
// NOTE: Workaround for limitation in ImageConsumer API // NOTE: Workaround for limitation in ImageConsumer API
// Convert int[] to short[], to be compatible with the ColorModel // Convert int[] to short[], to be compatible with the ColorModel
setPixelsImpl(pX, pY, pWeigth, pHeight, pModel, toShortPixels(pPixels), pOffset, pScanSize); setPixelsImpl(x, y, width, height, colorModel, toShortPixels(pixels), offset, scanSize);
} }
else { else {
setPixelsImpl(pX, pY, pWeigth, pHeight, pModel, pPixels, pOffset, pScanSize); setPixelsImpl(x, y, width, height, colorModel, pixels, offset, scanSize);
} }
} }
public void setProperties(Hashtable pProperties) { @Override
sourceProperties = pProperties; public void setProperties(Hashtable properties) {
sourceProperties = properties;
} }
} }
@@ -844,7 +844,7 @@ public final class ImageUtil {
return false; return false;
} }
for (int i = 0; i > mapSize1; i++) { for (int i = 0; i < mapSize1; i++) {
if (icm1.getRGB(i) != icm2.getRGB(i)) { if (icm1.getRGB(i) != icm2.getRGB(i)) {
return false; return false;
} }
@@ -34,14 +34,13 @@ import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import java.awt.*; import java.awt.*;
import java.awt.color.ColorSpace; import java.awt.color.*;
import java.awt.image.BufferedImage; import java.awt.image.*;
import java.awt.image.ColorModel;
import java.awt.image.ImageProducer;
import java.awt.image.IndexColorModel;
import java.net.URL; import java.net.URL;
import static org.junit.Assert.*; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
/** /**
* BufferedImageFactoryTestCase * BufferedImageFactoryTestCase
@@ -260,9 +259,9 @@ public class BufferedImageFactoryTest {
// Listener should abort ASAP // Listener should abort ASAP
factory.addProgressListener(new BufferedImageFactory.ProgressListener() { factory.addProgressListener(new BufferedImageFactory.ProgressListener() {
public void progress(BufferedImageFactory pFactory, float pPercentage) { public void progress(BufferedImageFactory factory, float percentage) {
if (pPercentage > 5) { if (percentage > 5) {
pFactory.abort(); factory.abort();
} }
} }
}); });
@@ -343,7 +342,7 @@ public class BufferedImageFactoryTest {
VerifyingListener listener = new VerifyingListener(factory); VerifyingListener listener = new VerifyingListener(factory);
factory.addProgressListener(listener); factory.addProgressListener(listener);
factory.removeProgressListener(new BufferedImageFactory.ProgressListener() { factory.removeProgressListener(new BufferedImageFactory.ProgressListener() {
public void progress(BufferedImageFactory pFactory, float pPercentage) { public void progress(BufferedImageFactory factory, float percentage) {
} }
}); });
factory.getBufferedImage(); factory.getBufferedImage();
@@ -380,11 +379,11 @@ public class BufferedImageFactoryTest {
this.factory = factory; this.factory = factory;
} }
public void progress(BufferedImageFactory pFactory, float pPercentage) { public void progress(BufferedImageFactory factory, float percentage) {
assertEquals(factory, pFactory); assertEquals(this.factory, factory);
assertTrue(pPercentage >= progress && pPercentage <= 100f); assertTrue(percentage >= progress && percentage <= 100f);
progress = pPercentage; progress = percentage;
} }
+10 -2
View File
@@ -4,13 +4,13 @@
<parent> <parent>
<groupId>com.twelvemonkeys.common</groupId> <groupId>com.twelvemonkeys.common</groupId>
<artifactId>common</artifactId> <artifactId>common</artifactId>
<version>3.9.0</version> <version>3.10.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>common-io</artifactId> <artifactId>common-io</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>TwelveMonkeys :: Common :: IO</name> <name>TwelveMonkeys :: Common :: IO</name>
<description> <description>
The TwelveMonkeys Common IO support TwelveMonkeys Common I/O support classes.
</description> </description>
<properties> <properties>
@@ -31,4 +31,12 @@
</dependency> </dependency>
</dependencies> </dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
</plugin>
</plugins>
</build>
</project> </project>
@@ -56,8 +56,8 @@ public class CompoundReader extends Reader {
private int currentReader; private int currentReader;
private int markedReader; private int markedReader;
private int mark; private long mark;
private int mNext; private long next;
/** /**
* Create a new compound reader. * 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 finalLock = pReaders; // NOTE: It's ok to sync on pReaders, as the
// reference can't change, only it's elements // reference can't change, only it's elements
readers = new ArrayList<Reader>(); readers = new ArrayList<>();
boolean markSupported = true; boolean markSupported = true;
while (pReaders.hasNext()) { 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! // NOTE: Reset mNext for every reader, and record marked reader in mark/reset methods!
mNext = 0; next = 0;
return current; return current;
} }
@@ -135,7 +135,7 @@ public class CompoundReader extends Reader {
synchronized (finalLock) { synchronized (finalLock) {
ensureOpen(); ensureOpen();
mark = mNext; mark = next;
markedReader = currentReader; markedReader = currentReader;
current.mark(pReadLimit); current.mark(pReadLimit);
@@ -158,7 +158,7 @@ public class CompoundReader extends Reader {
} }
current.reset(); current.reset();
mNext = mark; next = mark;
} }
} }
@@ -177,13 +177,13 @@ public class CompoundReader extends Reader {
return read(); // In case of 0-length readers return read(); // In case of 0-length readers
} }
mNext++; next++;
return read; 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) { synchronized (finalLock) {
int read = current.read(pBuffer, pOffset, pLength); 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 return read(pBuffer, pOffset, pLength); // In case of 0-length readers
} }
mNext += read; next += read;
return read; return read;
} }
@@ -213,7 +213,7 @@ public class CompoundReader extends Reader {
return skip(pChars); // In case of 0-length readers return skip(pChars); // In case of 0-length readers
} }
mNext += skipped; next += skipped;
return skipped; return skipped;
} }
@@ -50,8 +50,8 @@ public class StringArrayReader extends StringReader {
protected final Object finalLock; protected final Object finalLock;
private int currentSting; private int currentSting;
private int markedString; private int markedString;
private int mark; private long mark;
private int next; private long next;
/** /**
* Create a new string array reader. * 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) { synchronized (finalLock) {
int read = current.read(pBuffer, pOffset, pLength); int read = current.read(pBuffer, pOffset, pLength);
@@ -41,21 +41,20 @@ import java.io.InputStream;
* underlying stream. * underlying stream.
* *
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @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/io/SubStream.java#2 $
*/ */
public final class SubStream extends FilterInputStream { public final class SubStream extends FilterInputStream {
private long bytesLeft; private long bytesLeft;
private int markLimit; private int markLimit;
/** /**
* Creates a {@code SubStream} of the given {@code pStream}. * Creates a {@code SubStream} of the given {@code stream}.
* *
* @param pStream the underlying input stream * @param stream the underlying input stream
* @param pLength maximum number of bytes to read drom this stream * @param length maximum number of bytes to read from this stream
*/ */
public SubStream(final InputStream pStream, final long pLength) { public SubStream(final InputStream stream, final long length) {
super(Validate.notNull(pStream, "stream")); super(Validate.notNull(stream, "stream"));
bytesLeft = pLength; bytesLeft = Validate.isTrue(length >= 0, length, "length < 0: %s");
} }
/** /**
@@ -64,22 +63,23 @@ public final class SubStream extends FilterInputStream {
*/ */
@Override @Override
public void close() throws IOException { public void close() throws IOException {
// NOTE: Do not close the underlying stream // NOTE: Do not close the underlying stream, but consume it
while (bytesLeft > 0) { while (bytesLeft > 0) {
//noinspection ResultOfMethodCallIgnored if (skip(bytesLeft) <= 0 && read() < 0) {
skip(bytesLeft); break;
}
} }
} }
@Override @Override
public int available() throws IOException { public int available() throws IOException {
return (int) Math.min(super.available(), bytesLeft); return (int) findMaxLen(super.available());
} }
@Override @Override
public void mark(int pReadLimit) { public void mark(int readLimit) {
super.mark(pReadLimit);// This either succeeds or does nothing... super.mark(readLimit);// This either succeeds or does nothing...
markLimit = pReadLimit; markLimit = readLimit;
} }
@Override @Override
@@ -93,44 +93,42 @@ public final class SubStream extends FilterInputStream {
if (bytesLeft-- <= 0) { if (bytesLeft-- <= 0) {
return -1; return -1;
} }
return super.read(); return super.read();
} }
@Override @Override
public final int read(byte[] pBytes) throws IOException { public int read(byte[] bytes) throws IOException {
return read(pBytes, 0, pBytes.length); return read(bytes, 0, bytes.length);
} }
@Override @Override
public int read(final byte[] pBytes, final int pOffset, final int pLength) throws IOException { public int read(final byte[] bytes, final int off, final int len) throws IOException {
if (bytesLeft <= 0) { if (bytesLeft <= 0) {
return -1; return -1;
} }
int read = super.read(pBytes, pOffset, (int) findMaxLen(pLength)); int read = super.read(bytes, off, (int) findMaxLen(len));
bytesLeft = read < 0 ? 0 : bytesLeft - read; bytesLeft = read < 0 ? 0 : bytesLeft - read;
return read; return read;
} }
@Override
public long skip(long length) throws IOException {
long skipped = super.skip(findMaxLen(length)); // Skips 0 or more, never -1
bytesLeft -= skipped;
return skipped;
}
/** /**
* Finds the maximum number of bytes we can read or skip, from this stream. * Finds the maximum number of bytes we can read or skip, from this stream.
* *
* @param pLength the requested length * @param length the requested length
* @return the maximum number of bytes to read * @return the maximum number of bytes to read
*/ */
private long findMaxLen(long pLength) { private long findMaxLen(long length) {
if (bytesLeft < pLength) { return bytesLeft < length ? Math.max(bytesLeft, 0) : length;
return (int) Math.max(bytesLeft, 0);
}
else {
return pLength;
}
}
@Override
public long skip(long pLength) throws IOException {
long skipped = super.skip(findMaxLen(pLength));// Skips 0 or more, never -1
bytesLeft -= skipped;
return skipped;
} }
} }
@@ -0,0 +1,114 @@
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());
}
}
+10 -2
View File
@@ -4,17 +4,25 @@
<parent> <parent>
<groupId>com.twelvemonkeys.common</groupId> <groupId>com.twelvemonkeys.common</groupId>
<artifactId>common</artifactId> <artifactId>common</artifactId>
<version>3.9.0</version> <version>3.10.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>common-lang</artifactId> <artifactId>common-lang</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>TwelveMonkeys :: Common :: Language support</name> <name>TwelveMonkeys :: Common :: Language support</name>
<description> <description>
The TwelveMonkeys Common Language support TwelveMonkeys Common language support classes.
</description> </description>
<properties> <properties>
<project.jpms.module.name>com.twelvemonkeys.common.lang</project.jpms.module.name> <project.jpms.module.name>com.twelvemonkeys.common.lang</project.jpms.module.name>
</properties> </properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
</plugin>
</plugins>
</build>
</project> </project>
@@ -904,7 +904,7 @@ public final class StringUtil {
} }
catch (ParseException pe) { catch (ParseException pe) {
// Wrap in RuntimeException // Wrap in RuntimeException
throw new IllegalArgumentException(pe.getMessage()); throw new IllegalArgumentException(pe.getMessage() + " at pos " + pe.getErrorOffset());
} }
} }
@@ -593,8 +593,8 @@ public class StringUtilTest {
cal.clear(); cal.clear();
cal.set(Calendar.HOUR, 1); cal.set(Calendar.HOUR, 1);
cal.set(Calendar.MINUTE, 2); cal.set(Calendar.MINUTE, 2);
date = StringUtil.toDate("1:02 am", format = new SimpleDateFormat("HH:mm");
DateFormat.getTimeInstance(DateFormat.SHORT, Locale.US)); date = StringUtil.toDate("1:02", format);
assertNotNull(date); assertNotNull(date);
assertEquals(cal.getTime(), date); assertEquals(cal.getTime(), date);
} }
+2 -2
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys</groupId> <groupId>com.twelvemonkeys</groupId>
<artifactId>twelvemonkeys</artifactId> <artifactId>twelvemonkeys</artifactId>
<version>3.9.0</version> <version>3.10.2-SNAPSHOT</version>
</parent> </parent>
<groupId>com.twelvemonkeys.common</groupId> <groupId>com.twelvemonkeys.common</groupId>
<artifactId>common</artifactId> <artifactId>common</artifactId>
@@ -47,7 +47,7 @@
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<version>4.13.1</version> <version>4.13.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
+12 -3
View File
@@ -4,13 +4,13 @@
<parent> <parent>
<groupId>com.twelvemonkeys</groupId> <groupId>com.twelvemonkeys</groupId>
<artifactId>twelvemonkeys</artifactId> <artifactId>twelvemonkeys</artifactId>
<version>3.9.0</version> <version>3.10.2-SNAPSHOT</version>
</parent> </parent>
<groupId>com.twelvemonkeys.contrib</groupId> <groupId>com.twelvemonkeys.contrib</groupId>
<artifactId>contrib</artifactId> <artifactId>contrib</artifactId>
<name>TwelveMonkeys :: Contrib</name> <name>TwelveMonkeys :: Contrib</name>
<description> <description>
Contributions to TwelveMonkeys which are not matching into the ImageIO plug-ins. Contributions to TwelveMonkeys and code that doesn't fit anywhere else.
</description> </description>
<dependencies> <dependencies>
@@ -65,8 +65,17 @@
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<version>4.13.1</version> <version>4.13.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
</plugin>
</plugins>
</build>
</project> </project>
+15 -3
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.9.0</version> <version>3.10.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-batik</artifactId> <artifactId>imageio-batik</artifactId>
<name>TwelveMonkeys :: ImageIO :: Batik Plugin</name> <name>TwelveMonkeys :: ImageIO :: Batik Plugin</name>
@@ -17,7 +17,7 @@
<properties> <properties>
<project.jpms.module.name>com.twelvemonkeys.imageio.batik</project.jpms.module.name> <project.jpms.module.name>com.twelvemonkeys.imageio.batik</project.jpms.module.name>
<batik.version>1.15</batik.version> <batik.version>1.17</batik.version>
</properties> </properties>
<build> <build>
@@ -33,6 +33,18 @@
</systemPropertyVariables> </systemPropertyVariables>
</configuration> </configuration>
</plugin> </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> </plugins>
</build> </build>
@@ -51,7 +63,7 @@
<dependency> <dependency>
<groupId>commons-io</groupId> <groupId>commons-io</groupId>
<artifactId>commons-io</artifactId> <artifactId>commons-io</artifactId>
<version>2.11.0</version> <version>2.15.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@@ -33,6 +33,7 @@ package com.twelvemonkeys.imageio.plugins.svg;
import com.twelvemonkeys.image.ImageUtil; import com.twelvemonkeys.image.ImageUtil;
import com.twelvemonkeys.imageio.ImageReaderBase; import com.twelvemonkeys.imageio.ImageReaderBase;
import com.twelvemonkeys.imageio.util.IIOUtil; import com.twelvemonkeys.imageio.util.IIOUtil;
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
import com.twelvemonkeys.lang.StringUtil; import com.twelvemonkeys.lang.StringUtil;
import org.apache.batik.anim.dom.SVGDOMImplementation; import org.apache.batik.anim.dom.SVGDOMImplementation;
@@ -91,10 +92,10 @@ public class SVGImageReader extends ImageReaderBase {
/** /**
* Creates an {@code SVGImageReader}. * Creates an {@code SVGImageReader}.
* *
* @param pProvider the provider * @param provider the provider
*/ */
public SVGImageReader(final ImageReaderSpi pProvider) { public SVGImageReader(final ImageReaderSpi provider) {
super(pProvider); super(provider);
} }
protected void resetMembers() { protected void resetMembers() {
@@ -108,20 +109,20 @@ public class SVGImageReader extends ImageReaderBase {
} }
@Override @Override
public void setInput(Object pInput, boolean seekForwardOnly, boolean ignoreMetadata) { public void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) {
super.setInput(pInput, seekForwardOnly, ignoreMetadata); super.setInput(input, seekForwardOnly, ignoreMetadata);
if (imageInput != null) { if (imageInput != null) {
TranscoderInput input = new TranscoderInput(IIOUtil.createStreamAdapter(imageInput)); TranscoderInput transcoderInput = new TranscoderInput(IIOUtil.createStreamAdapter(imageInput));
rasterizer.setInput(input); rasterizer.setInput(transcoderInput);
} }
} }
public BufferedImage read(int pIndex, ImageReadParam pParam) throws IOException { public BufferedImage read(int imageIndex, ImageReadParam param) throws IOException {
checkBounds(pIndex); checkBounds(imageIndex);
if (pParam instanceof SVGReadParam) { if (param instanceof SVGReadParam) {
SVGReadParam svgParam = (SVGReadParam) pParam; SVGReadParam svgParam = (SVGReadParam) param;
// set the external-resource-resolution preference // set the external-resource-resolution preference
allowExternalResources = svgParam.isAllowExternalResources(); allowExternalResources = svgParam.isAllowExternalResources();
@@ -139,17 +140,17 @@ public class SVGImageReader extends ImageReaderBase {
} }
Dimension size = null; Dimension size = null;
if (pParam != null) { if (param != null) {
size = pParam.getSourceRenderSize(); size = param.getSourceRenderSize();
} }
if (size == null) { if (size == null) {
size = new Dimension(getWidth(pIndex), getHeight(pIndex)); size = new Dimension(getWidth(imageIndex), getHeight(imageIndex));
} }
BufferedImage destination = getDestination(pParam, getImageTypes(pIndex), size.width, size.height); BufferedImage destination = getDestination(param, getImageTypes(imageIndex), size.width, size.height);
// Read in the image, using the Batik Transcoder // Read in the image, using the Batik Transcoder
processImageStarted(pIndex); processImageStarted(imageIndex);
BufferedImage image = rasterizer.getImage(); BufferedImage image = rasterizer.getImage();
@@ -173,18 +174,18 @@ public class SVGImageReader extends ImageReaderBase {
return ex.getException() != null ? ex.getException() : ex; return ex.getException() != null ? ex.getException() : ex;
} }
private TranscodingHints paramsToHints(SVGReadParam pParam) throws IOException { private TranscodingHints paramsToHints(SVGReadParam param) throws IOException {
TranscodingHints hints = new TranscodingHints(); TranscodingHints hints = new TranscodingHints();
// Note: We must allow generic ImageReadParams, so converting to // Note: We must allow generic ImageReadParams, so converting to
// TanscodingHints should be done outside the SVGReadParam class. // TanscodingHints should be done outside the SVGReadParam class.
// Set dimensions // Set dimensions
Dimension size = pParam.getSourceRenderSize(); Dimension size = param.getSourceRenderSize();
Rectangle viewBox = rasterizer.getViewBox(); Rectangle viewBox = rasterizer.getViewBox();
if (size == null) { if (size == null) {
// SVG is not a pixel based format, but we'll scale it, according to // SVG is not a pixel based format, but we'll scale it, according to
// the subsampling for compatibility // the subsampling for compatibility
size = getSourceRenderSizeFromSubsamping(pParam, viewBox.getSize()); size = getSourceRenderSizeFromSubsamping(param, viewBox.getSize());
} }
if (size != null) { if (size != null) {
@@ -193,7 +194,7 @@ public class SVGImageReader extends ImageReaderBase {
} }
// Set area of interest // Set area of interest
Rectangle region = pParam.getSourceRegion(); Rectangle region = param.getSourceRegion();
if (region != null) { if (region != null) {
hints.put(ImageTranscoder.KEY_AOI, region); hints.put(ImageTranscoder.KEY_AOI, region);
@@ -217,7 +218,7 @@ public class SVGImageReader extends ImageReaderBase {
} }
// Background color // Background color
Paint bg = pParam.getBackgroundColor(); Paint bg = param.getBackgroundColor();
if (bg != null) { if (bg != null) {
hints.put(ImageTranscoder.KEY_BACKGROUND_COLOR, bg); hints.put(ImageTranscoder.KEY_BACKGROUND_COLOR, bg);
} }
@@ -225,10 +226,10 @@ public class SVGImageReader extends ImageReaderBase {
return hints; return hints;
} }
private Dimension getSourceRenderSizeFromSubsamping(ImageReadParam pParam, Dimension pOrigSize) { private Dimension getSourceRenderSizeFromSubsamping(ImageReadParam param, Dimension origSize) {
if (pParam.getSourceXSubsampling() > 1 || pParam.getSourceYSubsampling() > 1) { if (param.getSourceXSubsampling() > 1 || param.getSourceYSubsampling() > 1) {
return new Dimension((int) (pOrigSize.width / (float) pParam.getSourceXSubsampling()), return new Dimension((int) (origSize.width / (float) param.getSourceXSubsampling()),
(int) (pOrigSize.height / (float) pParam.getSourceYSubsampling())); (int) (origSize.height / (float) param.getSourceYSubsampling()));
} }
return null; return null;
} }
@@ -237,19 +238,19 @@ public class SVGImageReader extends ImageReaderBase {
return new SVGReadParam(); return new SVGReadParam();
} }
public int getWidth(int pIndex) throws IOException { public int getWidth(int imageIndex) throws IOException {
checkBounds(pIndex); checkBounds(imageIndex);
return rasterizer.getDefaultWidth(); return rasterizer.getDefaultWidth();
} }
public int getHeight(int pIndex) throws IOException { public int getHeight(int imageIndex) throws IOException {
checkBounds(pIndex); checkBounds(imageIndex);
return rasterizer.getDefaultHeight(); return rasterizer.getDefaultHeight();
} }
public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) { public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) {
return Collections.singleton(ImageTypeSpecifier.createFromRenderedImage(rasterizer.createImage(1, 1))).iterator(); return Collections.singleton(ImageTypeSpecifiers.createFromRenderedImage(rasterizer.createImage(1, 1))).iterator();
} }
/** /**
@@ -601,6 +602,7 @@ public class SVGImageReader extends ImageReaderBase {
initialized = true; initialized = true;
try { try {
super.addTranscodingHint(SVGAbstractTranscoder.KEY_ALLOW_EXTERNAL_RESOURCES, allowExternalResources);
super.transcode(transcoderInput, null); super.transcode(transcoderInput, null);
} }
catch (TranscoderException e) { catch (TranscoderException e) {
@@ -633,8 +635,8 @@ public class SVGImageReader extends ImageReaderBase {
return viewBox.getBounds(); return viewBox.getBounds();
} }
void setInput(final TranscoderInput pInput) { void setInput(final TranscoderInput input) {
transcoderInput = pInput; transcoderInput = input;
} }
@Override @Override
@@ -60,22 +60,22 @@ public final class SVGImageReaderSpi extends ImageReaderSpiBase {
super(new SVGProviderInfo()); super(new SVGProviderInfo());
} }
public boolean canDecodeInput(final Object pSource) throws IOException { public boolean canDecodeInput(final Object source) throws IOException {
return pSource instanceof ImageInputStream && canDecode((ImageInputStream) pSource); return source instanceof ImageInputStream && canDecode((ImageInputStream) source);
} }
@SuppressWarnings("StatementWithEmptyBody") @SuppressWarnings("StatementWithEmptyBody")
private static boolean canDecode(final ImageInputStream pInput) throws IOException { private static boolean canDecode(final ImageInputStream input) throws IOException {
// NOTE: This test is quite quick as it does not involve any parsing, // NOTE: This test is quite quick as it does not involve any parsing,
// however it may not recognize all kinds of SVG documents. // however it may not recognize all kinds of SVG documents.
try { try {
pInput.mark(); input.mark();
// TODO: This is not ok for UTF-16 and other wide encodings // TODO: This is not ok for UTF-16 and other wide encodings
// TODO: Use an XML (encoding) aware Reader instance instead // TODO: Use an XML (encoding) aware Reader instance instead
// Need to figure out pretty fast if this is XML or not // Need to figure out pretty fast if this is XML or not
int b; int b;
while (Character.isWhitespace((char) (b = pInput.read()))) { while (Character.isWhitespace((char) (b = input.read()))) {
// Skip over leading WS // Skip over leading WS
} }
@@ -95,30 +95,30 @@ public final class SVGImageReaderSpi extends ImageReaderSpiBase {
byte[] buffer = new byte[4]; byte[] buffer = new byte[4];
while (true) { while (true) {
pInput.readFully(buffer); input.readFully(buffer);
if (buffer[0] == '?') { if (buffer[0] == '?') {
// This is the XML declaration or a processing instruction // This is the XML declaration or a processing instruction
while (!((pInput.readByte() & 0xFF) == '?' && pInput.read() == '>')) { while (!((input.readByte() & 0xFF) == '?' && input.read() == '>')) {
// Skip until end of XML declaration or processing instruction or EOF // Skip until end of XML declaration or processing instruction or EOF
} }
} }
else if (buffer[0] == '!') { else if (buffer[0] == '!') {
if (buffer[1] == '-' && buffer[2] == '-') { if (buffer[1] == '-' && buffer[2] == '-') {
// This is a comment // This is a comment
while (!((pInput.readByte() & 0xFF) == '-' && pInput.read() == '-' && pInput.read() == '>')) { while (!((input.readByte() & 0xFF) == '-' && input.read() == '-' && input.read() == '>')) {
// Skip until end of comment or EOF // Skip until end of comment or EOF
} }
} }
else if (buffer[1] == 'D' && buffer[2] == 'O' && buffer[3] == 'C' else if (buffer[1] == 'D' && buffer[2] == 'O' && buffer[3] == 'C'
&& pInput.read() == 'T' && pInput.read() == 'Y' && input.read() == 'T' && input.read() == 'Y'
&& pInput.read() == 'P' && pInput.read() == 'E') { && input.read() == 'P' && input.read() == 'E') {
// This is the DOCTYPE declaration // This is the DOCTYPE declaration
while (Character.isWhitespace((char) (b = pInput.read()))) { while (Character.isWhitespace((char) (b = input.read()))) {
// Skip over WS // Skip over WS
} }
if (b == 's' && pInput.read() == 'v' && pInput.read() == 'g') { if (b == 's' && input.read() == 'v' && input.read() == 'g') {
// It's SVG, identified by DOCTYPE // It's SVG, identified by DOCTYPE
return true; return true;
} }
@@ -142,7 +142,7 @@ public final class SVGImageReaderSpi extends ImageReaderSpiBase {
return false; return false;
} }
while ((pInput.readByte() & 0xFF) != '<') { while ((input.readByte() & 0xFF) != '<') {
// Skip over, until next begin tag or EOF // Skip over, until next begin tag or EOF
} }
} }
@@ -153,7 +153,7 @@ public final class SVGImageReaderSpi extends ImageReaderSpiBase {
} }
finally { finally {
//noinspection ThrowFromFinallyBlock //noinspection ThrowFromFinallyBlock
pInput.reset(); input.reset();
} }
} }
@@ -51,16 +51,16 @@ public class SVGReadParam extends ImageReadParam {
return background; return background;
} }
public void setBackgroundColor(Paint pColor) { public void setBackgroundColor(Paint color) {
background = pColor; background = color;
} }
public String getBaseURI() { public String getBaseURI() {
return baseURI; return baseURI;
} }
public void setBaseURI(String pBaseURI) { public void setBaseURI(String baseURI) {
baseURI = pBaseURI; this.baseURI = baseURI;
} }
public void setAllowExternalResources(boolean allow) { public void setAllowExternalResources(boolean allow) {
+20 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.9.0</version> <version>3.10.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-bmp</artifactId> <artifactId>imageio-bmp</artifactId>
<name>TwelveMonkeys :: ImageIO :: BMP plugin</name> <name>TwelveMonkeys :: ImageIO :: BMP plugin</name>
@@ -26,4 +26,23 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </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> </project>
@@ -81,8 +81,8 @@ public final class BMPImageReader extends ImageReaderBase {
super(new BMPImageReaderSpi()); super(new BMPImageReaderSpi());
} }
BMPImageReader(final ImageReaderSpi pProvider) { BMPImageReader(final ImageReaderSpi provider) {
super(pProvider); super(provider);
} }
@Override @Override
@@ -129,6 +129,7 @@ public final class BMPImageReader extends ImageReaderBase {
// Read DIB header // Read DIB header
header = DIBHeader.read(imageInput); header = DIBHeader.read(imageInput);
// System.out.println("header = " + header);
if (pixelOffset < header.size + DIB.BMP_FILE_HEADER_SIZE) { if (pixelOffset < header.size + DIB.BMP_FILE_HEADER_SIZE) {
throw new IIOException("Invalid pixel offset: " + pixelOffset); throw new IIOException("Invalid pixel offset: " + pixelOffset);
@@ -186,30 +187,30 @@ public final class BMPImageReader extends ImageReaderBase {
} }
@Override @Override
public int getWidth(int pImageIndex) throws IOException { public int getWidth(int imageIndex) throws IOException {
checkBounds(pImageIndex); checkBounds(imageIndex);
return header.getWidth(); return header.getWidth();
} }
@Override @Override
public int getHeight(int pImageIndex) throws IOException { public int getHeight(int imageIndex) throws IOException {
checkBounds(pImageIndex); checkBounds(imageIndex);
return header.getHeight(); return header.getHeight();
} }
@Override @Override
public Iterator<ImageTypeSpecifier> getImageTypes(int pImageIndex) throws IOException { public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IOException {
checkBounds(pImageIndex); checkBounds(imageIndex);
// TODO: Better implementation, include INT_RGB types for 3BYTE_BGR and 4BYTE_ABGR for INT_ARGB // TODO: Better implementation, include INT_RGB types for 3BYTE_BGR and 4BYTE_ABGR for INT_ARGB
return Collections.singletonList(getRawImageType(pImageIndex)).iterator(); return Collections.singletonList(getRawImageType(imageIndex)).iterator();
} }
@Override @Override
public ImageTypeSpecifier getRawImageType(int pImageIndex) throws IOException { public ImageTypeSpecifier getRawImageType(int imageIndex) throws IOException {
checkBounds(pImageIndex); checkBounds(imageIndex);
if (header.getPlanes() != 1) { if (header.getPlanes() != 1) {
throw new IIOException("Multiple planes not supported"); throw new IIOException("Multiple planes not supported");
@@ -685,8 +686,8 @@ public final class BMPImageReader extends ImageReaderBase {
} }
@SuppressWarnings({ "unchecked", "UnusedDeclaration", "SameParameterValue" }) @SuppressWarnings({ "unchecked", "UnusedDeclaration", "SameParameterValue" })
static <T extends Throwable> void throwAs(final Class<T> pType, final Throwable pThrowable) throws T { static <T extends Throwable> void throwAs(final Class<T> type, final Throwable throwable) throws T {
throw (T) pThrowable; throw (T) throwable;
} }
private class ListenerDelegator extends ProgressListenerBase implements IIOReadUpdateListener, IIOReadWarningListener { private class ListenerDelegator extends ProgressListenerBase implements IIOReadUpdateListener, IIOReadWarningListener {
@@ -65,16 +65,16 @@ public final class BMPImageReaderSpi extends ImageReaderSpiBase {
} }
} }
public boolean canDecodeInput(final Object pSource) throws IOException { public boolean canDecodeInput(final Object source) throws IOException {
return pSource instanceof ImageInputStream && canDecode((ImageInputStream) pSource); return source instanceof ImageInputStream && canDecode((ImageInputStream) source);
} }
private static boolean canDecode(final ImageInputStream pInput) throws IOException { private static boolean canDecode(final ImageInputStream input) throws IOException {
byte[] fileHeader = new byte[18]; // Strictly: file header (14 bytes) + BMP header size field (4 bytes) byte[] fileHeader = new byte[18]; // Strictly: file header (14 bytes) + BMP header size field (4 bytes)
try { try {
pInput.mark(); input.mark();
pInput.readFully(fileHeader); input.readFully(fileHeader);
// Magic: BM // Magic: BM
if (fileHeader[0] != 'B' || fileHeader[1] != 'M') { if (fileHeader[0] != 'B' || fileHeader[1] != 'M') {
@@ -112,15 +112,15 @@ public final class BMPImageReaderSpi extends ImageReaderSpiBase {
} }
} }
finally { finally {
pInput.reset(); input.reset();
} }
} }
public ImageReader createReaderInstance(final Object pExtension) { public ImageReader createReaderInstance(final Object extension) {
return new BMPImageReader(this); return new BMPImageReader(this);
} }
public String getDescription(final Locale pLocale) { public String getDescription(final Locale locale) {
return "Windows Device Independent Bitmap Format (BMP) Reader"; return "Windows Device Independent Bitmap Format (BMP) Reader";
} }
} }
@@ -47,7 +47,7 @@ import java.nio.ByteOrder;
* BMPImageWriter * BMPImageWriter
*/ */
public final class BMPImageWriter extends DIBImageWriter { public final class BMPImageWriter extends DIBImageWriter {
protected BMPImageWriter(ImageWriterSpi provider) { BMPImageWriter(ImageWriterSpi provider) {
super(provider); super(provider);
} }
@@ -32,6 +32,7 @@ package com.twelvemonkeys.imageio.plugins.bmp;
import com.twelvemonkeys.imageio.AbstractMetadata; import com.twelvemonkeys.imageio.AbstractMetadata;
import com.twelvemonkeys.lang.Validate; import com.twelvemonkeys.lang.Validate;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import javax.imageio.metadata.IIOMetadataNode; import javax.imageio.metadata.IIOMetadataNode;
@@ -141,7 +142,7 @@ final class BMPMetadata extends AbstractMetadata {
@Override @Override
protected IIOMetadataNode getStandardChromaNode() { protected IIOMetadataNode getStandardChromaNode() {
// NOTE: BMP files may contain a color map, even if true color... // NOTE: BMP files may contain a color map, even if true color...
// Not sure if this is a good idea to expose to the meta data, // Not sure if this is a good idea to expose to the metadata,
// as it might be unexpected... Then again... // as it might be unexpected... Then again...
if (colorMap != null) { if (colorMap != null) {
IIOMetadataNode chroma = new IIOMetadataNode("Chroma"); IIOMetadataNode chroma = new IIOMetadataNode("Chroma");
@@ -29,11 +29,11 @@
*/ */
package com.twelvemonkeys.imageio.plugins.bmp; package com.twelvemonkeys.imageio.plugins.bmp;
import static com.twelvemonkeys.lang.Validate.notNull; import java.awt.image.*;
import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
import static com.twelvemonkeys.lang.Validate.notNull;
/** /**
* Describes a bitmap structure. * Describes a bitmap structure.
* *
@@ -47,9 +47,9 @@ abstract class BitmapDescriptor {
protected BufferedImage image; protected BufferedImage image;
protected BitmapMask mask; protected BitmapMask mask;
public BitmapDescriptor(final DirectoryEntry pEntry, final DIBHeader pHeader) { public BitmapDescriptor(final DirectoryEntry entry, final DIBHeader header) {
entry = notNull(pEntry, "entry");; this.entry = notNull(entry, "entry");
header = notNull(pHeader, "header"); this.header = notNull(header, "header");
} }
abstract public BufferedImage getImage() throws IOException; abstract public BufferedImage getImage() throws IOException;
@@ -75,7 +75,7 @@ abstract class BitmapDescriptor {
return getClass().getSimpleName() + "[" + entry + ", " + header + "]"; return getClass().getSimpleName() + "[" + entry + ", " + header + "]";
} }
public final void setMask(final BitmapMask mask) { final void setMask(final BitmapMask mask) {
this.mask = mask; this.mask = mask;
} }
@@ -29,10 +29,7 @@
*/ */
package com.twelvemonkeys.imageio.plugins.bmp; package com.twelvemonkeys.imageio.plugins.bmp;
import java.awt.image.BufferedImage; import java.awt.image.*;
import java.awt.image.DataBuffer;
import java.awt.image.IndexColorModel;
import java.awt.image.WritableRaster;
import java.util.Hashtable; import java.util.Hashtable;
/** /**
@@ -41,12 +38,13 @@ import java.util.Hashtable;
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @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$ * @version $Id: BitmapIndexed.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
*/ */
class BitmapIndexed extends BitmapDescriptor { final class BitmapIndexed extends BitmapDescriptor {
protected final int[] bits; final int[] bits;
protected final int[] colors; final int[] colors;
public BitmapIndexed(final DirectoryEntry entry, final DIBHeader header) {
super(entry, header);
public BitmapIndexed(final DirectoryEntry pEntry, final DIBHeader pHeader) {
super(pEntry, pHeader);
bits = new int[getWidth() * getHeight()]; bits = new int[getWidth() * getHeight()];
// NOTE: We're adding space for one extra color, for transparency // NOTE: We're adding space for one extra color, for transparency
@@ -59,20 +57,16 @@ class BitmapIndexed extends BitmapDescriptor {
IndexColorModel icm = createColorModel(); IndexColorModel icm = createColorModel();
// This is slightly obscure, and should probably be moved.. // We add cursor hotspot as a property to images created from CUR format.
// This is slightly obscure, and should probably be moved...
Hashtable<String, Object> properties = null; Hashtable<String, Object> properties = null;
if (entry instanceof DirectoryEntry.CUREntry) { if (entry instanceof DirectoryEntry.CUREntry) {
properties = new Hashtable<>(1); properties = new Hashtable<>(1);
properties.put("cursor_hotspot", ((DirectoryEntry.CUREntry) this.entry).getHotspot()); properties.put("cursor_hotspot", ((DirectoryEntry.CUREntry) this.entry).getHotspot());
} }
BufferedImage image = new BufferedImage( WritableRaster raster = icm.createCompatibleWritableRaster(getWidth(), getHeight());
icm, BufferedImage image = new BufferedImage(icm, raster, icm.isAlphaPremultiplied(), properties);
icm.createCompatibleWritableRaster(getWidth(), getHeight()),
icm.isAlphaPremultiplied(), properties
);
WritableRaster raster = image.getRaster();
// Make pixels transparent according to mask // Make pixels transparent according to mask
final int trans = icm.getTransparentPixel(); final int trans = icm.getTransparentPixel();
@@ -105,7 +99,7 @@ class BitmapIndexed extends BitmapDescriptor {
int index = findTransparentIndexMaybeRemap(this.colors, this.bits); int index = findTransparentIndexMaybeRemap(this.colors, this.bits);
if (index == -1) { if (index == -1) {
// No duplicate found, increase bitcount // No duplicate found, increase bit count
bits++; bits++;
transparent = this.colors.length - 1; transparent = this.colors.length - 1;
} }
@@ -117,10 +111,8 @@ class BitmapIndexed extends BitmapDescriptor {
} }
// NOTE: Setting hasAlpha to true, makes things work on 1.2 // NOTE: Setting hasAlpha to true, makes things work on 1.2
return new IndexColorModel( return new IndexColorModel(bits, colors, this.colors, 0, true, transparent,
bits, colors, this.colors, 0, true, transparent, bits <= 8 ? DataBuffer.TYPE_BYTE : DataBuffer.TYPE_USHORT);
bits <= 8 ? DataBuffer.TYPE_BYTE : DataBuffer.TYPE_USHORT
);
} }
private static int findTransparentIndexMaybeRemap(final int[] colors, final int[] bits) { private static int findTransparentIndexMaybeRemap(final int[] colors, final int[] bits) {
@@ -30,7 +30,7 @@
package com.twelvemonkeys.imageio.plugins.bmp; package com.twelvemonkeys.imageio.plugins.bmp;
import java.awt.image.BufferedImage; import java.awt.image.*;
/** /**
@@ -39,17 +39,17 @@ import java.awt.image.BufferedImage;
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @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$ * @version $Id: BitmapMask.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
*/ */
class BitmapMask extends BitmapDescriptor { final class BitmapMask extends BitmapDescriptor {
protected final BitmapIndexed bitMask; final BitmapIndexed bitMask;
public BitmapMask(final DirectoryEntry pParent, final DIBHeader pHeader) { public BitmapMask(final DirectoryEntry parent, final DIBHeader header) {
super(pParent, pHeader); super(parent, header);
bitMask = new BitmapIndexed(pParent, pHeader); bitMask = new BitmapIndexed(parent, header);
} }
boolean isTransparent(final int pX, final int pY) { boolean isTransparent(final int x, final int y) {
// NOTE: 1: Fully transparent, 0: Opaque... // NOTE: 1: Fully transparent, 0: Opaque...
return bitMask.bits[pX + pY * getWidth()] != 0; return bitMask.bits[x + y * getWidth()] != 0;
} }
public BufferedImage getImage() { public BufferedImage getImage() {
@@ -31,8 +31,7 @@
package com.twelvemonkeys.imageio.plugins.bmp; package com.twelvemonkeys.imageio.plugins.bmp;
import java.awt.*; import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.*;
import java.awt.image.WritableRaster;
/** /**
* Describes an RGB/true color bitmap structure (16, 24 and 32 bits per pixel). * Describes an RGB/true color bitmap structure (16, 24 and 32 bits per pixel).
@@ -40,10 +39,10 @@ import java.awt.image.WritableRaster;
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @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$ * @version $Id: BitmapRGB.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
*/ */
class BitmapRGB extends BitmapDescriptor { final class BitmapRGB extends BitmapDescriptor {
public BitmapRGB(final DirectoryEntry pEntry, final DIBHeader pHeader) { public BitmapRGB(final DirectoryEntry entry, final DIBHeader header) {
super(pEntry, pHeader); super(entry, header);
} }
@Override @Override
@@ -71,7 +70,7 @@ class BitmapRGB extends BitmapDescriptor {
WritableRaster alphaRaster = masked.getAlphaRaster(); WritableRaster alphaRaster = masked.getAlphaRaster();
byte[] trans = {0x0}; byte[] trans = {0x00};
for (int y = 0; y < getHeight(); y++) { for (int y = 0; y < getHeight(); y++) {
for (int x = 0; x < getWidth(); x++) { for (int x = 0; x < getWidth(); x++) {
if (mask.isTransparent(x, y)) { if (mask.isTransparent(x, y)) {
@@ -30,10 +30,9 @@
package com.twelvemonkeys.imageio.plugins.bmp; package com.twelvemonkeys.imageio.plugins.bmp;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.IIOException; import javax.imageio.IIOException;
import java.awt.image.*;
import java.io.IOException;
/** /**
* Represents bitmap structures we can't read. * Represents bitmap structures we can't read.
@@ -42,13 +41,13 @@ import javax.imageio.IIOException;
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> * @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$ * @version $Id: BitmapUnsupported.java,v 1.0 25.feb.2006 00:29:44 haku Exp$
*/ */
class BitmapUnsupported extends BitmapDescriptor { final class BitmapUnsupported extends BitmapDescriptor {
private String message; private final String message;
public BitmapUnsupported(final DirectoryEntry pEntry, DIBHeader header, final String pMessage) { public BitmapUnsupported(final DirectoryEntry entry, DIBHeader header, final String message) {
super(pEntry, header); super(entry, header);
message = pMessage; this.message = message;
} }
@Override @Override
@@ -48,22 +48,22 @@ public final class CURImageReader extends DIBImageReader {
super(new CURImageReaderSpi()); super(new CURImageReaderSpi());
} }
protected CURImageReader(final ImageReaderSpi pProvider) { CURImageReader(final ImageReaderSpi provider) {
super(pProvider); super(provider);
} }
/** /**
* Returns the hot spot location for the cursor. * Returns the hot spot location for the cursor.
* *
* @param pImageIndex the index of the cursor in the current input. * @param imageIndex the index of the cursor in the current input.
* @return the hot spot location for the cursor * @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 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 * @throws IndexOutOfBoundsException if {@code pImageIndex} is less than {@code 0} or greater than/equal to
* the number of cursors in the file * the number of cursors in the file
*/ */
public final Point getHotSpot(final int pImageIndex) throws IOException { public Point getHotSpot(final int imageIndex) throws IOException {
DirectoryEntry.CUREntry entry = (DirectoryEntry.CUREntry) getEntry(pImageIndex); DirectoryEntry.CUREntry entry = (DirectoryEntry.CUREntry) getEntry(imageIndex);
return entry.getHotspot(); return entry.getHotspot();
} }
} }
@@ -32,7 +32,6 @@ package com.twelvemonkeys.imageio.plugins.bmp;
import com.twelvemonkeys.imageio.spi.ImageReaderSpiBase; import com.twelvemonkeys.imageio.spi.ImageReaderSpiBase;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.ImageInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Locale; import java.util.Locale;
@@ -49,15 +48,15 @@ public final class CURImageReaderSpi extends ImageReaderSpiBase {
super(new CURProviderInfo()); super(new CURProviderInfo());
} }
public boolean canDecodeInput(final Object pSource) throws IOException { public boolean canDecodeInput(final Object source) throws IOException {
return pSource instanceof ImageInputStream && ICOImageReaderSpi.canDecode((ImageInputStream) pSource, DIB.TYPE_CUR); return source instanceof ImageInputStream && ICOImageReaderSpi.canDecode((ImageInputStream) source, DIB.TYPE_CUR);
} }
public ImageReader createReaderInstance(final Object pExtension) throws IOException { public CURImageReader createReaderInstance(final Object extension) {
return new CURImageReader(this); return new CURImageReader(this);
} }
public String getDescription(final Locale pLocale) { public String getDescription(final Locale locale) {
return "Windows Cursor Format (CUR) Reader"; return "Windows Cursor Format (CUR) Reader";
} }
} }
@@ -30,12 +30,11 @@
package com.twelvemonkeys.imageio.plugins.bmp; package com.twelvemonkeys.imageio.plugins.bmp;
import javax.imageio.IIOException;
import java.io.DataInput; import java.io.DataInput;
import java.io.DataOutput; import java.io.DataOutput;
import java.io.IOException; import java.io.IOException;
import javax.imageio.IIOException;
/** /**
* Represents the DIB (Device Independent Bitmap) Information header structure. * Represents the DIB (Device Independent Bitmap) Information header structure.
* *
@@ -91,17 +90,17 @@ abstract class DIBHeader {
protected DIBHeader() { protected DIBHeader() {
} }
public static DIBHeader read(final DataInput pStream) throws IOException { public static DIBHeader read(final DataInput stream) throws IOException {
int size = pStream.readInt(); int size = stream.readInt();
DIBHeader header = createHeader(size); DIBHeader header = createHeader(size);
header.read(size, pStream); header.read(size, stream);
return header; return header;
} }
private static DIBHeader createHeader(final int pSize) throws IOException { private static DIBHeader createHeader(final int size) throws IOException {
switch (pSize) { switch (size) {
case DIB.BITMAP_CORE_HEADER_SIZE: case DIB.BITMAP_CORE_HEADER_SIZE:
return new BitmapCoreHeader(); return new BitmapCoreHeader();
case DIB.OS2_V2_HEADER_16_SIZE: case DIB.OS2_V2_HEADER_16_SIZE:
@@ -118,11 +117,12 @@ abstract class DIBHeader {
case DIB.BITMAP_V5_INFO_HEADER_SIZE: case DIB.BITMAP_V5_INFO_HEADER_SIZE:
return new BitmapV5InfoHeader(); return new BitmapV5InfoHeader();
default: default:
throw new IIOException(String.format("Unknown Bitmap Information Header (size: %s)", pSize)); throw new IIOException(String.format("Unknown Bitmap Information Header (size: %s)", size));
} }
} }
protected abstract void read(int pSize, DataInput pStream) throws IOException; protected abstract void read(int size, DataInput stream) throws IOException;
protected abstract void write(final DataOutput stream) throws IOException;
public final int getSize() { public final int getSize() {
return size; return size;
@@ -189,12 +189,12 @@ abstract class DIBHeader {
); );
} }
private static int[] readMasks(final DataInput pStream, final boolean hasAlphaMask) throws IOException { private static int[] readMasks(final DataInput stream, final boolean hasAlphaMask) throws IOException {
int maskCount = hasAlphaMask ? 4 : 3; int maskCount = hasAlphaMask ? 4 : 3;
int[] masks = new int[4]; int[] masks = new int[4];
for (int i = 0; i < maskCount; i++) { for (int i = 0; i < maskCount; i++) {
masks[i] = pStream.readInt(); masks[i] = stream.readInt();
} }
return masks; return masks;
@@ -205,24 +205,30 @@ abstract class DIBHeader {
// TODO: Get rid of code duplication below... // TODO: Get rid of code duplication below...
static final class BitmapCoreHeader extends DIBHeader { static final class BitmapCoreHeader extends DIBHeader {
protected void read(final int pSize, final DataInput pStream) throws IOException { @Override
if (pSize != DIB.BITMAP_CORE_HEADER_SIZE) { protected void read(final int size, final DataInput stream) throws IOException {
throw new IIOException(String.format("Size: %s !=: %s", pSize, DIB.BITMAP_CORE_HEADER_SIZE)); if (size != DIB.BITMAP_CORE_HEADER_SIZE) {
throw new IIOException(String.format("Size: %s !=: %s", size, DIB.BITMAP_CORE_HEADER_SIZE));
} }
size = pSize; this.size = size;
// NOTE: Unlike all other headers, width and height are unsigned SHORT values (16 bit)! // NOTE: Unlike all other headers, width and height are unsigned SHORT values (16 bit)!
width = pStream.readUnsignedShort(); width = stream.readUnsignedShort();
height = pStream.readShort(); height = stream.readShort();
if (height < 0) { if (height < 0) {
height = -height; height = -height;
topDown = true; topDown = true;
} }
planes = pStream.readUnsignedShort(); planes = stream.readUnsignedShort();
bitCount = pStream.readUnsignedShort(); bitCount = stream.readUnsignedShort();
}
@Override
protected void write(DataOutput stream) {
throw new UnsupportedOperationException();
} }
public String getBMPVersion() { public String getBMPVersion() {
@@ -242,45 +248,51 @@ abstract class DIBHeader {
*/ */
static final class BitmapCoreHeaderV2 extends DIBHeader { static final class BitmapCoreHeaderV2 extends DIBHeader {
@SuppressWarnings("unused") @SuppressWarnings("unused")
protected void read(final int pSize, final DataInput pStream) throws IOException { @Override
if (pSize != DIB.OS2_V2_HEADER_SIZE && pSize != DIB.OS2_V2_HEADER_16_SIZE) { protected void read(final int size, final DataInput stream) throws IOException {
throw new IIOException(String.format("Size: %s !=: %s", pSize, DIB.OS2_V2_HEADER_SIZE)); 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));
} }
size = pSize; this.size = size;
width = pStream.readInt(); width = stream.readInt();
height = pStream.readInt(); height = stream.readInt();
if (height < 0) { if (height < 0) {
height = -height; height = -height;
topDown = true; topDown = true;
} }
planes = pStream.readUnsignedShort(); planes = stream.readUnsignedShort();
bitCount = pStream.readUnsignedShort(); bitCount = stream.readUnsignedShort();
if (pSize != DIB.OS2_V2_HEADER_16_SIZE) { if (size != DIB.OS2_V2_HEADER_16_SIZE) {
compression = pStream.readInt(); compression = stream.readInt();
imageSize = pStream.readInt(); imageSize = stream.readInt();
xPixelsPerMeter = pStream.readInt(); xPixelsPerMeter = stream.readInt();
yPixelsPerMeter = pStream.readInt(); yPixelsPerMeter = stream.readInt();
colorsUsed = pStream.readInt(); colorsUsed = stream.readInt();
colorsImportant = pStream.readInt(); colorsImportant = stream.readInt();
} }
// TODO: Use? These fields are not reflected in metadata as per now... // TODO: Use? These fields are not reflected in metadata as per now...
int units = pStream.readShort(); int units = stream.readShort();
int reserved = pStream.readShort(); int reserved = stream.readShort();
int recording = pStream.readShort(); // Recording algorithm int recording = stream.readShort(); // Recording algorithm
int rendering = pStream.readShort(); // Halftoning algorithm int rendering = stream.readShort(); // Halftoning algorithm
int size1 = pStream.readInt(); // Reserved for halftoning use int size1 = stream.readInt(); // Reserved for halftoning use
int size2 = pStream.readInt(); // Reserved for halftoning use int size2 = stream.readInt(); // Reserved for halftoning use
int colorEncoding = pStream.readInt(); // Color model used in bitmap int colorEncoding = stream.readInt(); // Color model used in bitmap
int identifier = pStream.readInt(); // Reserved for application use int identifier = stream.readInt(); // Reserved for application use
}
@Override
protected void write(DataOutput stream) {
throw new UnsupportedOperationException();
} }
public String getBMPVersion() { public String getBMPVersion() {
@@ -288,7 +300,6 @@ abstract class DIBHeader {
} }
} }
/** /**
* Represents the DIB (Device Independent Bitmap) Windows 3.0 Bitmap Information header structure. * 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 * This is the common format for persistent DIB structures, even if Windows
@@ -304,44 +315,46 @@ abstract class DIBHeader {
* @see <a href="https://forums.adobe.com/message/3272950#3272950">BITMAPV3INFOHEADER</a>. * @see <a href="https://forums.adobe.com/message/3272950#3272950">BITMAPV3INFOHEADER</a>.
*/ */
static final class BitmapInfoHeader extends DIBHeader { static final class BitmapInfoHeader extends DIBHeader {
protected void read(final int pSize, final DataInput pStream) throws IOException { @Override
if (!(pSize == DIB.BITMAP_INFO_HEADER_SIZE || pSize == DIB.BITMAP_V2_INFO_HEADER_SIZE || pSize == DIB.BITMAP_V3_INFO_HEADER_SIZE)) { protected void read(final int size, final DataInput stream) throws IOException {
throw new IIOException(String.format("Size: %s !=: %s", pSize, DIB.BITMAP_INFO_HEADER_SIZE)); 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));
} }
size = pSize; this.size = size;
width = pStream.readInt(); width = stream.readInt();
height = pStream.readInt(); height = stream.readInt();
if (height < 0) { if (height < 0) {
height = -height; height = -height;
topDown = true; topDown = true;
} }
planes = pStream.readUnsignedShort(); planes = stream.readUnsignedShort();
bitCount = pStream.readUnsignedShort(); bitCount = stream.readUnsignedShort();
compression = pStream.readInt(); compression = stream.readInt();
imageSize = pStream.readInt(); imageSize = stream.readInt();
xPixelsPerMeter = pStream.readInt(); xPixelsPerMeter = stream.readInt();
yPixelsPerMeter = pStream.readInt(); yPixelsPerMeter = stream.readInt();
colorsUsed = pStream.readInt(); colorsUsed = stream.readInt();
colorsImportant = pStream.readInt(); colorsImportant = stream.readInt();
// Read masks if we have V2 or V3 // Read masks if we have V2 or V3
// or if we have compression BITFIELDS or ALPHA_BITFIELDS // or if we have compression BITFIELDS or ALPHA_BITFIELDS
if (size == DIB.BITMAP_V2_INFO_HEADER_SIZE || compression == DIB.COMPRESSION_BITFIELDS) { if (this.size == DIB.BITMAP_V2_INFO_HEADER_SIZE || compression == DIB.COMPRESSION_BITFIELDS) {
masks = readMasks(pStream, false); masks = readMasks(stream, false);
} }
else if (size == DIB.BITMAP_V3_INFO_HEADER_SIZE || compression == DIB.COMPRESSION_ALPHA_BITFIELDS) { else if (this.size == DIB.BITMAP_V3_INFO_HEADER_SIZE || compression == DIB.COMPRESSION_ALPHA_BITFIELDS) {
masks = readMasks(pStream, true); masks = readMasks(stream, true);
} }
} }
void write(final DataOutput stream) throws IOException { @Override
protected void write(final DataOutput stream) throws IOException {
stream.writeInt(DIB.BITMAP_INFO_HEADER_SIZE); stream.writeInt(DIB.BITMAP_INFO_HEADER_SIZE);
stream.writeInt(width); stream.writeInt(width);
@@ -359,7 +372,7 @@ abstract class DIBHeader {
stream.writeInt(colorsUsed); stream.writeInt(colorsUsed);
stream.writeInt(colorsImportant); stream.writeInt(colorsImportant);
// TODO: Write masks, if bitfields // TODO: Write masks, if COMPRESSION_BITFIELDS/COMPRESSION_ALPHA_BITFIELDS
} }
public String getBMPVersion() { public String getBMPVersion() {
@@ -376,105 +389,160 @@ abstract class DIBHeader {
* Represents the BITMAPV4INFOHEADER structure. * Represents the BITMAPV4INFOHEADER structure.
*/ */
static final class BitmapV4InfoHeader extends DIBHeader { static final class BitmapV4InfoHeader extends DIBHeader {
protected void read(final int pSize, final DataInput pStream) throws IOException { @Override
if (pSize != DIB.BITMAP_V4_INFO_HEADER_SIZE) { protected void read(final int size, final DataInput stream) throws IOException {
throw new IIOException(String.format("Size: %s !=: %s", pSize, DIB.BITMAP_V4_INFO_HEADER_SIZE)); if (size != DIB.BITMAP_V4_INFO_HEADER_SIZE) {
throw new IIOException(String.format("Size: %s !=: %s", size, DIB.BITMAP_V4_INFO_HEADER_SIZE));
} }
size = pSize; this.size = size;
width = pStream.readInt(); width = stream.readInt();
height = pStream.readInt(); height = stream.readInt();
if (height < 0) { if (height < 0) {
height = -height; height = -height;
topDown = true; topDown = true;
} }
planes = pStream.readUnsignedShort(); planes = stream.readUnsignedShort();
bitCount = pStream.readUnsignedShort(); bitCount = stream.readUnsignedShort();
compression = pStream.readInt(); compression = stream.readInt();
imageSize = pStream.readInt(); imageSize = stream.readInt();
xPixelsPerMeter = pStream.readInt(); xPixelsPerMeter = stream.readInt();
yPixelsPerMeter = pStream.readInt(); yPixelsPerMeter = stream.readInt();
colorsUsed = pStream.readInt(); colorsUsed = stream.readInt();
colorsImportant = pStream.readInt(); colorsImportant = stream.readInt();
masks = readMasks(pStream, true); masks = readMasks(stream, true);
colorSpaceType = pStream.readInt(); // Should be 0 for V4 colorSpaceType = stream.readInt(); // Should be 0 for V4
cieXYZEndpoints = new double[9]; cieXYZEndpoints = new double[9];
for (int i = 0; i < cieXYZEndpoints.length; i++) { for (int i = 0; i < cieXYZEndpoints.length; i++) {
cieXYZEndpoints[i] = pStream.readInt(); // TODO: Hmmm...? cieXYZEndpoints[i] = stream.readInt(); // TODO: Hmmm...?
} }
gamma = new int[3]; gamma = new int[3];
for (int i = 0; i < gamma.length; i++) { for (int i = 0; i < gamma.length; i++) {
gamma[i] = pStream.readInt(); gamma[i] = stream.readInt();
} }
} }
public String getBMPVersion() { public String getBMPVersion() {
return "BMP v. 4.x"; 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. * Represents the BITMAPV5INFOHEADER structure.
*/ */
static final class BitmapV5InfoHeader extends DIBHeader { static final class BitmapV5InfoHeader extends DIBHeader {
protected void read(final int pSize, final DataInput pStream) throws IOException { protected void read(final int size, final DataInput stream) throws IOException {
if (pSize != DIB.BITMAP_V5_INFO_HEADER_SIZE) { if (size != DIB.BITMAP_V5_INFO_HEADER_SIZE) {
throw new IIOException(String.format("Size: %s !=: %s", pSize, DIB.BITMAP_V5_INFO_HEADER_SIZE)); throw new IIOException(String.format("Size: %s !=: %s", size, DIB.BITMAP_V5_INFO_HEADER_SIZE));
} }
size = pSize; this.size = size;
width = pStream.readInt(); width = stream.readInt();
height = pStream.readInt(); height = stream.readInt();
if (height < 0) { if (height < 0) {
height = -height; height = -height;
topDown = true; topDown = true;
} }
planes = pStream.readUnsignedShort(); planes = stream.readUnsignedShort();
bitCount = pStream.readUnsignedShort(); bitCount = stream.readUnsignedShort();
compression = pStream.readInt(); compression = stream.readInt();
imageSize = pStream.readInt(); imageSize = stream.readInt();
xPixelsPerMeter = pStream.readInt(); xPixelsPerMeter = stream.readInt();
yPixelsPerMeter = pStream.readInt(); yPixelsPerMeter = stream.readInt();
colorsUsed = pStream.readInt(); colorsUsed = stream.readInt();
colorsImportant = pStream.readInt(); colorsImportant = stream.readInt();
masks = readMasks(pStream, true); masks = readMasks(stream, true);
colorSpaceType = pStream.readInt(); colorSpaceType = stream.readInt();
cieXYZEndpoints = new double[9]; cieXYZEndpoints = new double[9];
for (int i = 0; i < cieXYZEndpoints.length; i++) { for (int i = 0; i < cieXYZEndpoints.length; i++) {
cieXYZEndpoints[i] = pStream.readInt(); // TODO: Hmmm...? cieXYZEndpoints[i] = stream.readInt(); // TODO: Hmmm...?
} }
gamma = new int[3]; gamma = new int[3];
for (int i = 0; i < gamma.length; i++) { for (int i = 0; i < gamma.length; i++) {
gamma[i] = pStream.readInt(); gamma[i] = stream.readInt();
} }
intent = pStream.readInt(); // TODO: Verify if this is same as ICC intent intent = stream.readInt(); // TODO: Verify if this is same as ICC intent
profileData = pStream.readInt() & 0xffffffffL; profileData = stream.readInt() & 0xffffffffL;
profileSize = pStream.readInt() & 0xffffffffL; profileSize = stream.readInt() & 0xffffffffL;
pStream.readInt(); // Reserved stream.readInt(); // Reserved
}
@Override
protected void write(DataOutput stream) {
throw new UnsupportedOperationException();
} }
public String getBMPVersion() { public String getBMPVersion() {
@@ -30,19 +30,11 @@
package com.twelvemonkeys.imageio.plugins.bmp; package com.twelvemonkeys.imageio.plugins.bmp;
import java.awt.*; import com.twelvemonkeys.image.ImageUtil;
import java.awt.color.ColorSpace; import com.twelvemonkeys.imageio.ImageReaderBase;
import java.awt.event.WindowAdapter; import com.twelvemonkeys.imageio.stream.SubImageInputStream;
import java.awt.event.WindowEvent; import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
import java.awt.image.*; import com.twelvemonkeys.util.WeakWeakMap;
import java.io.File;
import java.io.IOException;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import javax.imageio.IIOException; import javax.imageio.IIOException;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
@@ -52,12 +44,18 @@ import javax.imageio.ImageTypeSpecifier;
import javax.imageio.spi.ImageReaderSpi; import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.ImageInputStream;
import javax.swing.*; import javax.swing.*;
import java.awt.*;
import com.twelvemonkeys.image.ImageUtil; import java.awt.color.*;
import com.twelvemonkeys.imageio.ImageReaderBase; import java.awt.event.*;
import com.twelvemonkeys.imageio.stream.SubImageInputStream; import java.awt.image.*;
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers; import java.io.File;
import com.twelvemonkeys.util.WeakWeakMap; import java.io.IOException;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
/** /**
* ImageReader for Microsoft Windows ICO (icon) format. * ImageReader for Microsoft Windows ICO (icon) format.
@@ -81,13 +79,13 @@ abstract class DIBImageReader extends ImageReaderBase {
private Directory directory; private Directory directory;
// TODO: Review these, make sure we don't have a memory leak // TODO: Review these, make sure we don't have a memory leak
private Map<DirectoryEntry, DIBHeader> headers = new WeakHashMap<>(); private final Map<DirectoryEntry, DIBHeader> headers = new WeakHashMap<>();
private Map<DirectoryEntry, BitmapDescriptor> descriptors = new WeakWeakMap<>(); private final Map<DirectoryEntry, BitmapDescriptor> descriptors = new WeakWeakMap<>();
private ImageReader pngImageReader; private ImageReader pngImageReader;
protected DIBImageReader(final ImageReaderSpi pProvider) { protected DIBImageReader(final ImageReaderSpi provider) {
super(pProvider); super(provider);
} }
protected void resetMembers() { protected void resetMembers() {
@@ -102,8 +100,8 @@ abstract class DIBImageReader extends ImageReaderBase {
} }
} }
public Iterator<ImageTypeSpecifier> getImageTypes(final int pImageIndex) throws IOException { public Iterator<ImageTypeSpecifier> getImageTypes(final int imageIndex) throws IOException {
DirectoryEntry entry = getEntry(pImageIndex); DirectoryEntry entry = getEntry(imageIndex);
// NOTE: Delegate to PNG reader // NOTE: Delegate to PNG reader
if (isPNG(entry)) { if (isPNG(entry)) {
@@ -155,39 +153,39 @@ abstract class DIBImageReader extends ImageReaderBase {
return getDirectory().count(); return getDirectory().count();
} }
public int getWidth(final int pImageIndex) throws IOException { public int getWidth(final int imageIndex) throws IOException {
return getEntry(pImageIndex).getWidth(); return getEntry(imageIndex).getWidth();
} }
public int getHeight(final int pImageIndex) throws IOException { public int getHeight(final int imageIndex) throws IOException {
return getEntry(pImageIndex).getHeight(); return getEntry(imageIndex).getHeight();
} }
public BufferedImage read(final int pImageIndex, final ImageReadParam pParam) throws IOException { public BufferedImage read(final int imageIndex, final ImageReadParam param) throws IOException {
checkBounds(pImageIndex); checkBounds(imageIndex);
processImageStarted(pImageIndex); processImageStarted(imageIndex);
DirectoryEntry entry = getEntry(pImageIndex); DirectoryEntry entry = getEntry(imageIndex);
BufferedImage destination; BufferedImage destination;
if (isPNG(entry)) { if (isPNG(entry)) {
// NOTE: Special case for Windows Vista, 256x256 PNG encoded images, with no DIB header... // NOTE: Special case for Windows Vista, 256x256 PNG encoded images, with no DIB header...
destination = readPNG(entry, pParam); destination = readPNG(entry, param);
} }
else { else {
// NOTE: If param does not have explicit destination, we'll try to create a BufferedImage later, // 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 // to allow for storing the cursor hotspot for CUR images
destination = hasExplicitDestination(pParam) ? destination = hasExplicitDestination(param) ?
getDestination(pParam, getImageTypes(pImageIndex), getWidth(pImageIndex), getHeight(pImageIndex)) : null; getDestination(param, getImageTypes(imageIndex), getWidth(imageIndex), getHeight(imageIndex)) : null;
BufferedImage image = readBitmap(entry); BufferedImage image = readBitmap(entry);
// TODO: Handle AOI and subsampling inline, probably not of big importance... // TODO: Handle AOI and subsampling inline, probably not of big importance...
if (pParam != null) { if (param != null) {
image = fakeAOI(image, pParam); image = fakeAOI(image, param);
image = ImageUtil.toBuffered(fakeSubsampling(image, pParam)); image = ImageUtil.toBuffered(fakeSubsampling(image, param));
} }
if (destination == null) { if (destination == null) {
@@ -213,10 +211,10 @@ abstract class DIBImageReader extends ImageReaderBase {
return destination; return destination;
} }
private boolean isPNG(final DirectoryEntry pEntry) throws IOException { private boolean isPNG(final DirectoryEntry entry) throws IOException {
long magic; long magic;
imageInput.seek(pEntry.getOffset()); imageInput.seek(entry.getOffset());
imageInput.setByteOrder(ByteOrder.BIG_ENDIAN); imageInput.setByteOrder(ByteOrder.BIG_ENDIAN);
try { try {
@@ -229,22 +227,20 @@ abstract class DIBImageReader extends ImageReaderBase {
return magic == DIB.PNG_MAGIC; return magic == DIB.PNG_MAGIC;
} }
private BufferedImage readPNG(final DirectoryEntry pEntry, final ImageReadParam pParam) throws IOException { private BufferedImage readPNG(final DirectoryEntry entry, final ImageReadParam param) throws IOException {
// TODO: Consider delegating listener calls // TODO: Consider delegating listener calls
return initPNGReader(pEntry).read(0, pParam); return initPNGReader(entry).read(0, param);
} }
private Iterator<ImageTypeSpecifier> getImageTypesPNG(final DirectoryEntry pEntry) throws IOException { private Iterator<ImageTypeSpecifier> getImageTypesPNG(final DirectoryEntry entry) throws IOException {
return initPNGReader(pEntry).getImageTypes(0); return initPNGReader(entry).getImageTypes(0);
} }
private ImageReader initPNGReader(final DirectoryEntry pEntry) throws IOException { private ImageReader initPNGReader(final DirectoryEntry entry) throws IOException {
ImageReader pngReader = getPNGReader(); ImageReader pngReader = getPNGReader();
imageInput.seek(pEntry.getOffset()); imageInput.seek(entry.getOffset());
// InputStream inputStream = IIOUtil.createStreamAdapter(imageInput, pEntry.getSize()); ImageInputStream stream = new SubImageInputStream(imageInput, entry.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 // NOTE: Will throw IOException on later reads if input is not PNG
pngReader.setInput(stream); pngReader.setInput(stream);
@@ -271,31 +267,31 @@ abstract class DIBImageReader extends ImageReaderBase {
return pngImageReader; return pngImageReader;
} }
private DIBHeader getHeader(final DirectoryEntry pEntry) throws IOException { private DIBHeader getHeader(final DirectoryEntry entry) throws IOException {
if (!headers.containsKey(pEntry)) { if (!headers.containsKey(entry)) {
imageInput.seek(pEntry.getOffset()); imageInput.seek(entry.getOffset());
DIBHeader header = DIBHeader.read(imageInput); DIBHeader header = DIBHeader.read(imageInput);
headers.put(pEntry, header); headers.put(entry, header);
} }
return headers.get(pEntry); return headers.get(entry);
} }
private BufferedImage readBitmap(final DirectoryEntry pEntry) throws IOException { private BufferedImage readBitmap(final DirectoryEntry entry) throws IOException {
// TODO: Get rid of the caching, as the images are mutable // TODO: Get rid of the caching, as the images are mutable
BitmapDescriptor descriptor = descriptors.get(pEntry); BitmapDescriptor descriptor = descriptors.get(entry);
if (descriptor == null || !descriptors.containsKey(pEntry)) { if (descriptor == null || !descriptors.containsKey(entry)) {
DIBHeader header = getHeader(pEntry); DIBHeader header = getHeader(entry);
int offset = pEntry.getOffset() + header.getSize(); int offset = entry.getOffset() + header.getSize();
if (offset != imageInput.getStreamPosition()) { if (offset != imageInput.getStreamPosition()) {
imageInput.seek(offset); imageInput.seek(offset);
} }
// TODO: Support this, it's already in the BMP reader, spec allows RLE4 and RLE8 // TODO: Support this, it's already in the BMP reader, spec allows RLE4 and RLE8
if (header.getCompression() != DIB.COMPRESSION_RGB) { if (header.getCompression() != DIB.COMPRESSION_RGB) {
descriptor = new BitmapUnsupported(pEntry, header, String.format("Unsupported compression: %d", header.getCompression())); descriptor = new BitmapUnsupported(entry, header, String.format("Unsupported compression: %d", header.getCompression()));
} }
else { else {
int bitCount = header.getBitCount(); int bitCount = header.getBitCount();
@@ -305,75 +301,75 @@ abstract class DIBImageReader extends ImageReaderBase {
case 1: case 1:
case 4: case 4:
case 8: // TODO: Gray! case 8: // TODO: Gray!
descriptor = new BitmapIndexed(pEntry, header); descriptor = new BitmapIndexed(entry, header);
readBitmapIndexed((BitmapIndexed) descriptor); readBitmapIndexed((BitmapIndexed) descriptor);
break; break;
// RGB style // RGB style
case 16: case 16:
descriptor = new BitmapRGB(pEntry, header); descriptor = new BitmapRGB(entry, header);
readBitmap16(descriptor); readBitmap16(descriptor);
break; break;
case 24: case 24:
descriptor = new BitmapRGB(pEntry, header); descriptor = new BitmapRGB(entry, header);
readBitmap24(descriptor); readBitmap24(descriptor);
break; break;
case 32: case 32:
descriptor = new BitmapRGB(pEntry, header); descriptor = new BitmapRGB(entry, header);
readBitmap32(descriptor); readBitmap32(descriptor);
break; break;
default: default:
descriptor = new BitmapUnsupported(pEntry, header, String.format("Unsupported bit count %d", bitCount)); descriptor = new BitmapUnsupported(entry, header, String.format("Unsupported bit count %d", bitCount));
} }
} }
descriptors.put(pEntry, descriptor); descriptors.put(entry, descriptor);
} }
return descriptor.getImage(); return descriptor.getImage();
} }
private void readBitmapIndexed(final BitmapIndexed pBitmap) throws IOException { private void readBitmapIndexed(final BitmapIndexed bitmap) throws IOException {
readColorMap(pBitmap); readColorMap(bitmap);
switch (pBitmap.getBitCount()) { switch (bitmap.getBitCount()) {
case 1: case 1:
readBitmapIndexed1(pBitmap, false); readBitmapIndexed1(bitmap, false);
break; break;
case 4: case 4:
readBitmapIndexed4(pBitmap); readBitmapIndexed4(bitmap);
break; break;
case 8: case 8:
readBitmapIndexed8(pBitmap); readBitmapIndexed8(bitmap);
break; break;
} }
BitmapMask mask = new BitmapMask(pBitmap.entry, pBitmap.header); BitmapMask mask = new BitmapMask(bitmap.entry, bitmap.header);
readBitmapIndexed1(mask.bitMask, true); readBitmapIndexed1(mask.bitMask, true);
pBitmap.setMask(mask); bitmap.setMask(mask);
} }
private void readColorMap(final BitmapIndexed pBitmap) throws IOException { private void readColorMap(final BitmapIndexed bitmap) throws IOException {
int colorCount = pBitmap.getColorCount(); int colorCount = bitmap.getColorCount();
for (int i = 0; i < colorCount; i++) { for (int i = 0; i < colorCount; i++) {
// aRGB (a is "Reserved") // aRGB (a is "Reserved")
pBitmap.colors[i] = (imageInput.readInt() & 0xffffff) | 0xff000000; bitmap.colors[i] = (imageInput.readInt() & 0xffffff) | 0xff000000;
} }
} }
private void readBitmapIndexed1(final BitmapIndexed pBitmap, final boolean pAsMask) throws IOException { private void readBitmapIndexed1(final BitmapIndexed bitmap, final boolean asMask) throws IOException {
int width = adjustToPadding((pBitmap.getWidth() + 7) >> 3); int width = adjustToPadding((bitmap.getWidth() + 7) >> 3);
byte[] row = new byte[width]; byte[] row = new byte[width];
for (int y = 0; y < pBitmap.getHeight(); y++) { for (int y = 0; y < bitmap.getHeight(); y++) {
imageInput.readFully(row, 0, width); imageInput.readFully(row, 0, width);
int rowPos = 0; int rowPos = 0;
int xOrVal = 0x80; int xOrVal = 0x80;
int pos = (pBitmap.getHeight() - y - 1) * pBitmap.getWidth(); int pos = (bitmap.getHeight() - y - 1) * bitmap.getWidth();
for (int x = 0; x < pBitmap.getWidth(); x++) { for (int x = 0; x < bitmap.getWidth(); x++) {
pBitmap.bits[pos++] = ((row[rowPos] & xOrVal) / xOrVal) & 0xFF; bitmap.bits[pos++] = ((row[rowPos] & xOrVal) / xOrVal) & 0xFF;
if (xOrVal == 1) { if (xOrVal == 1) {
xOrVal = 0x80; xOrVal = 0x80;
@@ -384,29 +380,29 @@ abstract class DIBImageReader extends ImageReaderBase {
} }
} }
// NOTE: If we are reading the mask, we don't abort or report progress // NOTE: If we are reading the mask, we can't abort or report progress
if (!pAsMask) { if (!asMask) {
if (abortRequested()) { if (abortRequested()) {
processReadAborted(); processReadAborted();
break; break;
} }
processImageProgress(100 * y / (float) pBitmap.getHeight()); processImageProgress(100 * y / (float) bitmap.getHeight());
} }
} }
} }
private void readBitmapIndexed4(final BitmapIndexed pBitmap) throws IOException { private void readBitmapIndexed4(final BitmapIndexed bitmap) throws IOException {
int width = adjustToPadding((pBitmap.getWidth() + 1) >> 1); int width = adjustToPadding((bitmap.getWidth() + 1) >> 1);
byte[] row = new byte[width]; byte[] row = new byte[width];
for (int y = 0; y < pBitmap.getHeight(); y++) { for (int y = 0; y < bitmap.getHeight(); y++) {
imageInput.readFully(row, 0, width); imageInput.readFully(row, 0, width);
int rowPos = 0; int rowPos = 0;
boolean high4 = true; boolean high4 = true;
int pos = (pBitmap.getHeight() - y - 1) * pBitmap.getWidth(); int pos = (bitmap.getHeight() - y - 1) * bitmap.getWidth();
for (int x = 0; x < pBitmap.getWidth(); x++) { for (int x = 0; x < bitmap.getWidth(); x++) {
int value; int value;
if (high4) { if (high4) {
@@ -417,7 +413,7 @@ abstract class DIBImageReader extends ImageReaderBase {
rowPos++; rowPos++;
} }
pBitmap.bits[pos++] = value & 0xFF; bitmap.bits[pos++] = value & 0xFF;
high4 = !high4; high4 = !high4;
} }
@@ -426,22 +422,22 @@ abstract class DIBImageReader extends ImageReaderBase {
break; break;
} }
processImageProgress(100 * y / (float) pBitmap.getHeight()); processImageProgress(100 * y / (float) bitmap.getHeight());
} }
} }
private void readBitmapIndexed8(final BitmapIndexed pBitmap) throws IOException { private void readBitmapIndexed8(final BitmapIndexed bitmap) throws IOException {
int width = adjustToPadding(pBitmap.getWidth()); int width = adjustToPadding(bitmap.getWidth());
byte[] row = new byte[width]; byte[] row = new byte[width];
for (int y = 0; y < pBitmap.getHeight(); y++) { for (int y = 0; y < bitmap.getHeight(); y++) {
imageInput.readFully(row, 0, width); imageInput.readFully(row, 0, width);
int rowPos = 0; int rowPos = 0;
int pos = (pBitmap.getHeight() - y - 1) * pBitmap.getWidth(); int pos = (bitmap.getHeight() - y - 1) * bitmap.getWidth();
for (int x = 0; x < pBitmap.getWidth(); x++) { for (int x = 0; x < bitmap.getWidth(); x++) {
pBitmap.bits[pos++] = row[rowPos++] & 0xFF; bitmap.bits[pos++] = row[rowPos++] & 0xFF;
} }
if (abortRequested()) { if (abortRequested()) {
@@ -449,40 +445,41 @@ abstract class DIBImageReader extends ImageReaderBase {
break; break;
} }
processImageProgress(100 * y / (float) pBitmap.getHeight()); processImageProgress(100 * y / (float) bitmap.getHeight());
} }
} }
/** /**
* @param pWidth Bytes per scan line (i.e., 1BPP, width = 9 -> bytes = 1) * @param width Bytes per scan line (i.e., 1BPP, width = 9 -> bytes = 2)
* @return padded width * @return padded width
*/ */
private static int adjustToPadding(final int pWidth) { private static int adjustToPadding(final int width) {
if ((pWidth & 0x03) != 0) { if ((width & 0x03) != 0) {
return (pWidth & ~0x03) + 4; return (width & ~0x03) + 4;
} }
return pWidth;
return width;
} }
private void readBitmap16(final BitmapDescriptor pBitmap) throws IOException { private void readBitmap16(final BitmapDescriptor bitmap) throws IOException {
short[] pixels = new short[pBitmap.getWidth() * pBitmap.getHeight()]; short[] pixels = new short[bitmap.getWidth() * bitmap.getHeight()];
// TODO: Support TYPE_USHORT_565 and the RGB 444/ARGB 4444 layouts // TODO: Support TYPE_USHORT_565 and the RGB 444/ARGB 4444 layouts
// Will create TYPE_USHORT_555 // Will create TYPE_USHORT_555
DirectColorModel cm = new DirectColorModel(16, 0x7C00, 0x03E0, 0x001F); DirectColorModel cm = new DirectColorModel(16, 0x7C00, 0x03E0, 0x001F);
DataBuffer buffer = new DataBufferUShort(pixels, pixels.length); DataBuffer buffer = new DataBufferUShort(pixels, pixels.length);
WritableRaster raster = Raster.createPackedRaster( WritableRaster raster = Raster.createPackedRaster(
buffer, pBitmap.getWidth(), pBitmap.getHeight(), pBitmap.getWidth(), cm.getMasks(), null buffer, bitmap.getWidth(), bitmap.getHeight(), bitmap.getWidth(), cm.getMasks(), null
); );
pBitmap.image = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null); bitmap.image = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
for (int y = 0; y < pBitmap.getHeight(); y++) { for (int y = 0; y < bitmap.getHeight(); y++) {
int offset = (pBitmap.getHeight() - y - 1) * pBitmap.getWidth(); int offset = (bitmap.getHeight() - y - 1) * bitmap.getWidth();
imageInput.readFully(pixels, offset, pBitmap.getWidth()); imageInput.readFully(pixels, offset, bitmap.getWidth());
// Skip to 32 bit boundary // Skip to 32 bit boundary
if (pBitmap.getWidth() % 2 != 0) { if (bitmap.getWidth() % 2 != 0) {
imageInput.readShort(); imageInput.readShort();
} }
@@ -491,14 +488,14 @@ abstract class DIBImageReader extends ImageReaderBase {
break; break;
} }
processImageProgress(100 * y / (float) pBitmap.getHeight()); processImageProgress(100 * y / (float) bitmap.getHeight());
} }
// TODO: Might be mask!? // TODO: Might be mask!?
} }
private void readBitmap24(final BitmapDescriptor pBitmap) throws IOException { private void readBitmap24(final BitmapDescriptor bitmap) throws IOException {
byte[] pixels = new byte[pBitmap.getWidth() * pBitmap.getHeight() * 3]; byte[] pixels = new byte[bitmap.getWidth() * bitmap.getHeight() * 3];
// Create TYPE_3BYTE_BGR // Create TYPE_3BYTE_BGR
DataBuffer buffer = new DataBufferByte(pixels, pixels.length); DataBuffer buffer = new DataBufferByte(pixels, pixels.length);
@@ -509,17 +506,17 @@ abstract class DIBImageReader extends ImageReaderBase {
cs, nBits, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE cs, nBits, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE
); );
int scanlineStride = pBitmap.getWidth() * 3; int scanlineStride = bitmap.getWidth() * 3;
// BMP rows are padded to 4 byte boundary // BMP rows are padded to 4 byte boundary
int rowSizeBytes = ((8 * scanlineStride + 31) / 32) * 4; int rowSizeBytes = ((8 * scanlineStride + 31) / 32) * 4;
WritableRaster raster = Raster.createInterleavedRaster( WritableRaster raster = Raster.createInterleavedRaster(
buffer, pBitmap.getWidth(), pBitmap.getHeight(), scanlineStride, 3, bOffs, null buffer, bitmap.getWidth(), bitmap.getHeight(), scanlineStride, 3, bOffs, null
); );
pBitmap.image = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null); bitmap.image = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
for (int y = 0; y < pBitmap.getHeight(); y++) { for (int y = 0; y < bitmap.getHeight(); y++) {
int offset = (pBitmap.getHeight() - y - 1) * scanlineStride; int offset = (bitmap.getHeight() - y - 1) * scanlineStride;
imageInput.readFully(pixels, offset, scanlineStride); imageInput.readFully(pixels, offset, scanlineStride);
imageInput.skipBytes(rowSizeBytes - scanlineStride); imageInput.skipBytes(rowSizeBytes - scanlineStride);
@@ -528,38 +525,38 @@ abstract class DIBImageReader extends ImageReaderBase {
break; break;
} }
processImageProgress(100 * y / (float) pBitmap.getHeight()); processImageProgress(100 * y / (float) bitmap.getHeight());
} }
// 24 bit icons usually have a bit mask // 24 bit icons usually have a bit mask
if (pBitmap.hasMask()) { if (bitmap.hasMask()) {
BitmapMask mask = new BitmapMask(pBitmap.entry, pBitmap.header); BitmapMask mask = new BitmapMask(bitmap.entry, bitmap.header);
readBitmapIndexed1(mask.bitMask, true); readBitmapIndexed1(mask.bitMask, true);
pBitmap.setMask(mask); bitmap.setMask(mask);
} }
} }
private void readBitmap32(final BitmapDescriptor pBitmap) throws IOException { private void readBitmap32(final BitmapDescriptor bitmap) throws IOException {
int[] pixels = new int[pBitmap.getWidth() * pBitmap.getHeight()]; int[] pixels = new int[bitmap.getWidth() * bitmap.getHeight()];
// Will create TYPE_INT_ARGB // Will create TYPE_INT_ARGB
DirectColorModel cm = (DirectColorModel) ColorModel.getRGBdefault(); DirectColorModel cm = (DirectColorModel) ColorModel.getRGBdefault();
DataBuffer buffer = new DataBufferInt(pixels, pixels.length); DataBuffer buffer = new DataBufferInt(pixels, pixels.length);
WritableRaster raster = Raster.createPackedRaster( WritableRaster raster = Raster.createPackedRaster(
buffer, pBitmap.getWidth(), pBitmap.getHeight(), pBitmap.getWidth(), cm.getMasks(), null buffer, bitmap.getWidth(), bitmap.getHeight(), bitmap.getWidth(), cm.getMasks(), null
); );
pBitmap.image = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null); bitmap.image = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
for (int y = 0; y < pBitmap.getHeight(); y++) { for (int y = 0; y < bitmap.getHeight(); y++) {
int offset = (pBitmap.getHeight() - y - 1) * pBitmap.getWidth(); int offset = (bitmap.getHeight() - y - 1) * bitmap.getWidth();
imageInput.readFully(pixels, offset, pBitmap.getWidth()); imageInput.readFully(pixels, offset, bitmap.getWidth());
if (abortRequested()) { if (abortRequested()) {
processReadAborted(); processReadAborted();
break; break;
} }
processImageProgress(100 * y / (float) pBitmap.getHeight()); processImageProgress(100 * y / (float) bitmap.getHeight());
} }
// There might be a mask here as well, but we'll ignore it, // There might be a mask here as well, but we'll ignore it,
@@ -590,18 +587,18 @@ abstract class DIBImageReader extends ImageReaderBase {
directory = Directory.read(type, imageCount, imageInput); directory = Directory.read(type, imageCount, imageInput);
} }
final DirectoryEntry getEntry(final int pImageIndex) throws IOException { final DirectoryEntry getEntry(final int imageIndex) throws IOException {
Directory directory = getDirectory(); Directory directory = getDirectory();
if (pImageIndex < 0 || pImageIndex >= directory.count()) { if (imageIndex < 0 || imageIndex >= directory.count()) {
throw new IndexOutOfBoundsException(String.format("Index: %d, ImageCount: %d", pImageIndex, directory.count())); throw new IndexOutOfBoundsException(String.format("Index: %d, ImageCount: %d", imageIndex, directory.count()));
} }
return directory.getEntry(pImageIndex); return directory.getEntry(imageIndex);
} }
/// Test code below, ignore.. :-) /// Test code below, ignore.. :-)
public static void main(final String[] pArgs) throws IOException { public static void main(final String[] args) throws IOException {
if (pArgs.length == 0) { if (args.length == 0) {
System.err.println("Please specify the icon file name"); System.err.println("Please specify the icon file name");
System.exit(1); System.exit(1);
} }
@@ -613,7 +610,7 @@ abstract class DIBImageReader extends ImageReaderBase {
// Ignore // Ignore
} }
String title = new File(pArgs[0]).getName(); String title = new File(args[0]).getName();
JFrame frame = createWindow(title); JFrame frame = createWindow(title);
JPanel root = new JPanel(new FlowLayout()); JPanel root = new JPanel(new FlowLayout());
JScrollPane scroll = JScrollPane scroll =
@@ -629,7 +626,7 @@ abstract class DIBImageReader extends ImageReaderBase {
ImageReader reader = readers.next(); ImageReader reader = readers.next();
for (String arg : pArgs) { for (String arg : args) {
JPanel panel = new JPanel(null); JPanel panel = new JPanel(null);
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
readImagesInFile(arg, reader, panel); readImagesInFile(arg, reader, panel);
@@ -640,28 +637,28 @@ abstract class DIBImageReader extends ImageReaderBase {
frame.setVisible(true); frame.setVisible(true);
} }
private static void readImagesInFile(String pFileName, ImageReader pReader, final Container pContainer) throws IOException { private static void readImagesInFile(String fileName, ImageReader reader, final Container container) throws IOException {
File file = new File(pFileName); File file = new File(fileName);
if (!file.isFile()) { if (!file.isFile()) {
System.err.println(pFileName + " not found, or is no file"); System.err.println(fileName + " not found, or is no file");
} }
pReader.setInput(ImageIO.createImageInputStream(file)); reader.setInput(ImageIO.createImageInputStream(file));
int imageCount = pReader.getNumImages(true); int imageCount = reader.getNumImages(true);
for (int i = 0; i < imageCount; i++) { for (int i = 0; i < imageCount; i++) {
try { try {
addImage(pContainer, pReader, i); addImage(container, reader, i);
} }
catch (Exception e) { catch (Exception e) {
System.err.println("FileName: " + pFileName); System.err.println("FileName: " + fileName);
System.err.println("Icon: " + i); System.err.println("Icon: " + i);
e.printStackTrace(); e.printStackTrace();
} }
} }
} }
private static JFrame createWindow(final String pTitle) { private static JFrame createWindow(final String title) {
JFrame frame = new JFrame(pTitle); JFrame frame = new JFrame(title);
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.addWindowListener(new WindowAdapter() { frame.addWindowListener(new WindowAdapter() {
public void windowClosed(WindowEvent e) { public void windowClosed(WindowEvent e) {
@@ -671,15 +668,15 @@ abstract class DIBImageReader extends ImageReaderBase {
return frame; return frame;
} }
private static void addImage(final Container pParent, final ImageReader pReader, final int pImageNo) throws IOException { private static void addImage(final Container parent, final ImageReader reader, final int imageNo) throws IOException {
final JButton button = new JButton(); final JButton button = new JButton();
BufferedImage image = pReader.read(pImageNo); BufferedImage image = reader.read(imageNo);
button.setIcon(new ImageIcon(image) { button.setIcon(new ImageIcon(image) {
TexturePaint texture; TexturePaint texture;
private void createTexture(final GraphicsConfiguration pGraphicsConfiguration) { private void createTexture(final GraphicsConfiguration graphicsConfiguration) {
BufferedImage pattern = pGraphicsConfiguration.createCompatibleImage(20, 20); BufferedImage pattern = graphicsConfiguration.createCompatibleImage(20, 20);
Graphics2D g = pattern.createGraphics(); Graphics2D g = pattern.createGraphics();
try { try {
g.setColor(Color.LIGHT_GRAY); g.setColor(Color.LIGHT_GRAY);
@@ -714,6 +711,6 @@ abstract class DIBImageReader extends ImageReaderBase {
String.valueOf(((IndexColorModel) image.getColorModel()).getMapSize()) : String.valueOf(((IndexColorModel) image.getColorModel()).getMapSize()) :
"TrueColor")); "TrueColor"));
pParent.add(button); parent.add(button);
} }
} }
@@ -44,24 +44,25 @@ import java.util.List;
class Directory { class Directory {
private final List<DirectoryEntry> entries; private final List<DirectoryEntry> entries;
private Directory(int pImageCount) { private Directory(int imageCount) {
entries = Arrays.asList(new DirectoryEntry[pImageCount]); entries = Arrays.asList(new DirectoryEntry[imageCount]);
} }
public static Directory read(final int pType, final int pImageCount, final DataInput pStream) throws IOException { public static Directory read(final int type, final int imageCount, final DataInput stream) throws IOException {
Directory directory = new Directory(pImageCount); Directory directory = new Directory(imageCount);
directory.readEntries(pType, pStream); directory.readEntries(type, stream);
return directory; return directory;
} }
private void readEntries(final int pType, final DataInput pStream) throws IOException { private void readEntries(final int type, final DataInput stream) throws IOException {
for (int i = 0; i < entries.size(); i++) { for (int i = 0; i < entries.size(); i++) {
entries.set(i, DirectoryEntry.read(pType, pStream)); entries.set(i, DirectoryEntry.read(type, stream));
} }
} }
public DirectoryEntry getEntry(final int pEntryIndex) { public DirectoryEntry getEntry(final int entryIndex) {
return entries.get(pEntryIndex); return entries.get(entryIndex);
} }
public int count() { public int count() {
@@ -32,8 +32,7 @@ package com.twelvemonkeys.imageio.plugins.bmp;
import javax.imageio.IIOException; import javax.imageio.IIOException;
import java.awt.*; import java.awt.*;
import java.awt.image.ColorModel; import java.awt.image.*;
import java.awt.image.IndexColorModel;
import java.io.DataInput; import java.io.DataInput;
import java.io.DataOutput; import java.io.DataOutput;
import java.io.IOException; import java.io.IOException;
@@ -58,47 +57,43 @@ abstract class DirectoryEntry {
DirectoryEntry() { DirectoryEntry() {
} }
public static DirectoryEntry read(final int pType, final DataInput pStream) throws IOException { public static DirectoryEntry read(final int type, final DataInput stream) throws IOException {
DirectoryEntry entry = createEntry(pType); DirectoryEntry entry = createEntry(type);
entry.read(pStream); entry.read(stream);
return entry; return entry;
} }
private static DirectoryEntry createEntry(int pType) throws IIOException { private static DirectoryEntry createEntry(int type) throws IIOException {
switch (pType) { switch (type) {
case DIB.TYPE_ICO: case DIB.TYPE_ICO:
return new ICOEntry(); return new ICOEntry();
case DIB.TYPE_CUR: case DIB.TYPE_CUR:
return new CUREntry(); return new CUREntry();
default: default:
throw new IIOException( throw new IIOException(String.format("Unknown DIB type: %s, expected: %s (ICO) or %s (CUR)", type, DIB.TYPE_ICO, DIB.TYPE_CUR));
String.format(
"Unknown DIB type: %s, expected: %s (ICO) or %s (CUR)",
pType, DIB.TYPE_ICO, DIB.TYPE_CUR
)
);
} }
} }
protected void read(final DataInput pStream) throws IOException { protected void read(final DataInput stream) throws IOException {
// Width/height = 0, means 256 // Width/height = 0, means 256
int w = pStream.readUnsignedByte(); int w = stream.readUnsignedByte();
width = w == 0 ? 256 : w; width = w == 0 ? 256 : w;
int h = pStream.readUnsignedByte(); int h = stream.readUnsignedByte();
height = h == 0 ? 256 : h; height = h == 0 ? 256 : h;
// Color count = 0, means 256 or more colors // Color count = 0, means 256 or more colors
colorCount = pStream.readUnsignedByte(); colorCount = stream.readUnsignedByte();
// Ignore. Should be 0, but .NET (System.Drawing.Icon.Save) sets this value to 255, according to Wikipedia // Ignore. Should be 0, but .NET (System.Drawing.Icon.Save) sets this value to 255, according to Wikipedia
pStream.readUnsignedByte(); stream.readUnsignedByte();
planes = pStream.readUnsignedShort(); // Should be 0 or 1 for ICO, x hotspot for CUR planes = stream.readUnsignedShort(); // Should be 0 or 1 for ICO, x hotspot for CUR
bitCount = pStream.readUnsignedShort(); // bit count for ICO, y hotspot for CUR bitCount = stream.readUnsignedShort(); // bit count for ICO, y hotspot for CUR
// Size of bitmap in bytes // Size of bitmap in bytes
size = pStream.readInt(); size = stream.readInt();
offset = pStream.readInt(); offset = stream.readInt();
} }
void write(final DataOutput output) throws IOException { void write(final DataOutput output) throws IOException {
@@ -157,8 +152,8 @@ abstract class DirectoryEntry {
private int yHotspot; private int yHotspot;
@Override @Override
protected void read(final DataInput pStream) throws IOException { protected void read(final DataInput stream) throws IOException {
super.read(pStream); super.read(stream);
// NOTE: This is a hack... // NOTE: This is a hack...
xHotspot = planes; xHotspot = planes;
@@ -46,7 +46,7 @@ public final class ICOImageReader extends DIBImageReader {
super(new ICOImageReaderSpi()); super(new ICOImageReaderSpi());
} }
protected ICOImageReader(final ImageReaderSpi pProvider) { ICOImageReader(final ImageReaderSpi provider) {
super(pProvider); super(provider);
} }
} }
@@ -32,7 +32,6 @@ package com.twelvemonkeys.imageio.plugins.bmp;
import com.twelvemonkeys.imageio.spi.ImageReaderSpiBase; import com.twelvemonkeys.imageio.spi.ImageReaderSpiBase;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.ImageInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Locale; import java.util.Locale;
@@ -49,32 +48,32 @@ public final class ICOImageReaderSpi extends ImageReaderSpiBase {
super(new ICOProviderInfo()); super(new ICOProviderInfo());
} }
public boolean canDecodeInput(final Object pSource) throws IOException { public boolean canDecodeInput(final Object source) throws IOException {
return pSource instanceof ImageInputStream && canDecode((ImageInputStream) pSource, DIB.TYPE_ICO); return source instanceof ImageInputStream && canDecode((ImageInputStream) source, DIB.TYPE_ICO);
} }
static boolean canDecode(final ImageInputStream pInput, final int pType) throws IOException { static boolean canDecode(final ImageInputStream input, final int type) throws IOException {
byte[] signature = new byte[4]; byte[] signature = new byte[4];
try { try {
pInput.mark(); input.mark();
pInput.readFully(signature); input.readFully(signature);
int count = pInput.readByte() + (pInput.readByte() << 8); int count = input.readByte() + (input.readByte() << 8);
return (signature[0] == 0x0 && signature[1] == 0x0 && signature[2] == pType return (signature[0] == 0x0 && signature[1] == 0x0 && signature[2] == type
&& signature[3] == 0x0 && count > 0); && signature[3] == 0x0 && count > 0);
} }
finally { finally {
pInput.reset(); input.reset();
} }
} }
public ImageReader createReaderInstance(final Object pExtension) throws IOException { public ICOImageReader createReaderInstance(final Object extension) {
return new ICOImageReader(this); return new ICOImageReader(this);
} }
public String getDescription(final Locale pLocale) { public String getDescription(final Locale locale) {
return "Windows Icon Format (ICO) Reader"; return "Windows Icon Format (ICO) Reader";
} }
} }
@@ -33,15 +33,19 @@ package com.twelvemonkeys.imageio.plugins.bmp;
import com.twelvemonkeys.imageio.stream.SubImageOutputStream; import com.twelvemonkeys.imageio.stream.SubImageOutputStream;
import com.twelvemonkeys.imageio.util.ProgressListenerBase; import com.twelvemonkeys.imageio.util.ProgressListenerBase;
import javax.imageio.*; 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.event.IIOWriteWarningListener; import javax.imageio.event.IIOWriteWarningListener;
import javax.imageio.metadata.IIOMetadata; import javax.imageio.metadata.IIOMetadata;
import javax.imageio.spi.ImageWriterSpi; import javax.imageio.spi.ImageWriterSpi;
import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream; import javax.imageio.stream.ImageOutputStream;
import java.awt.image.BufferedImage; import java.awt.image.*;
import java.awt.image.ColorModel;
import java.awt.image.RenderedImage;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.Iterator; import java.util.Iterator;
@@ -64,7 +68,7 @@ public final class ICOImageWriter extends DIBImageWriter {
private ImageWriter pngDelegate; private ImageWriter pngDelegate;
protected ICOImageWriter(final ImageWriterSpi provider) { ICOImageWriter(final ImageWriterSpi provider) {
super(provider); super(provider);
} }
@@ -124,7 +128,7 @@ public final class ICOImageWriter extends DIBImageWriter {
} }
@Override @Override
public void endWriteSequence() throws IOException { public void endWriteSequence() {
assertOutput(); assertOutput();
if (sequenceIndex < 0) { if (sequenceIndex < 0) {
@@ -30,24 +30,14 @@
package com.twelvemonkeys.imageio.plugins.bmp; package com.twelvemonkeys.imageio.plugins.bmp;
import static org.junit.Assert.*; import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
import static org.junit.Assume.assumeNoException; import com.twelvemonkeys.xml.XMLSerializer;
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 java.awt.*; import org.junit.Ignore;
import java.awt.image.BufferedImage; import org.junit.Test;
import java.io.ByteArrayOutputStream; import org.mockito.InOrder;
import java.io.IOException; import org.w3c.dom.Node;
import java.lang.reflect.Constructor; import org.w3c.dom.NodeList;
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.IIOException;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
@@ -57,16 +47,25 @@ import javax.imageio.ImageTypeSpecifier;
import javax.imageio.event.IIOReadProgressListener; import javax.imageio.event.IIOReadProgressListener;
import javax.imageio.metadata.IIOMetadata; import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode; import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.spi.IIORegistry;
import javax.imageio.spi.ImageReaderSpi; 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 org.junit.Ignore; import static org.junit.Assert.*;
import org.junit.Test; import static org.junit.Assume.assumeNoException;
import org.mockito.InOrder; import static org.mockito.ArgumentMatchers.anyFloat;
import org.w3c.dom.Node; import static org.mockito.ArgumentMatchers.eq;
import org.w3c.dom.NodeList; import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.inOrder;
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest; import static org.mockito.Mockito.mock;
import com.twelvemonkeys.xml.XMLSerializer;
/** /**
* BMPImageReaderTest * BMPImageReaderTest
@@ -326,10 +325,8 @@ public class BMPImageReaderTest extends ImageReaderAbstractTest<BMPImageReader>
public void testMetadataEqualsJRE() throws IOException { public void testMetadataEqualsJRE() throws IOException {
ImageReader jreReader; ImageReader jreReader;
try { try {
@SuppressWarnings("unchecked") ImageReaderSpi provider = (ImageReaderSpi) IIORegistry.getDefaultInstance().getServiceProviderByClass(Class.forName("com.sun.imageio.plugins.bmp.BMPImageReaderSpi"));
Class<ImageReader> jreReaderClass = (Class<ImageReader>) Class.forName("com.sun.imageio.plugins.bmp.BMPImageReader"); jreReader = provider.createReaderInstance();
Constructor<ImageReader> constructor = jreReaderClass.getConstructor(ImageReaderSpi.class);
jreReader = constructor.newInstance(new Object[] {null});
} }
catch (Exception e) { catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
+10 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.9.0</version> <version>3.10.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-clippath</artifactId> <artifactId>imageio-clippath</artifactId>
<name>TwelveMonkeys :: ImageIO :: Photoshop Path Support</name> <name>TwelveMonkeys :: ImageIO :: Photoshop Path Support</name>
@@ -32,4 +32,13 @@
<artifactId>imageio-metadata</artifactId> <artifactId>imageio-metadata</artifactId>
</dependency> </dependency>
</dependencies> </dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
</plugin>
</plugins>
</build>
</project> </project>
@@ -42,6 +42,7 @@ import com.twelvemonkeys.imageio.metadata.tiff.TIFF;
import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader; import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader;
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream; import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
import com.twelvemonkeys.imageio.stream.SubImageInputStream; import com.twelvemonkeys.imageio.stream.SubImageInputStream;
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
import javax.imageio.*; import javax.imageio.*;
import javax.imageio.metadata.IIOMetadata; import javax.imageio.metadata.IIOMetadata;
@@ -307,7 +308,7 @@ public final class Paths {
throw new IllegalArgumentException("output == null!"); throw new IllegalArgumentException("output == null!");
} }
ImageTypeSpecifier type = ImageTypeSpecifier.createFromRenderedImage(image); ImageTypeSpecifier type = ImageTypeSpecifiers.createFromRenderedImage(image);
Iterator<ImageWriter> writers = ImageIO.getImageWriters(type, formatName); Iterator<ImageWriter> writers = ImageIO.getImageWriters(type, formatName);
if (writers.hasNext()) { if (writers.hasNext()) {
+20 -1
View File
@@ -4,10 +4,13 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.9.0</version> <version>3.10.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-core</artifactId> <artifactId>imageio-core</artifactId>
<name>TwelveMonkeys :: ImageIO :: Core</name> <name>TwelveMonkeys :: ImageIO :: Core</name>
<description>
TwelveMonkeys ImageIO core support classes.
</description>
<properties> <properties>
<project.jpms.module.name>com.twelvemonkeys.imageio.core</project.jpms.module.name> <project.jpms.module.name>com.twelvemonkeys.imageio.core</project.jpms.module.name>
@@ -28,4 +31,20 @@
</dependency> </dependency>
</dependencies> </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> </project>
@@ -188,7 +188,7 @@ public final class ColorSpaces {
// Will throw IllegalArgumentException or CMMException if the profile is bad // Will throw IllegalArgumentException or CMMException if the profile is bad
cs.fromRGB(new float[] {0.999f, 0.5f, 0.001f}); cs.fromRGB(new float[] {0.999f, 0.5f, 0.001f});
// This breaks *some times* after validation of bad profiles, // This breaks *sometimes* after validation of bad profiles,
// we'll let it blow up early in this case // we'll let it blow up early in this case
cs.getProfile().getData(); cs.getProfile().getData();
} }
@@ -31,6 +31,7 @@
package com.twelvemonkeys.imageio.stream; package com.twelvemonkeys.imageio.stream;
import javax.imageio.stream.ImageInputStreamImpl; import javax.imageio.stream.ImageInputStreamImpl;
import java.io.Closeable;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
@@ -52,6 +53,10 @@ import static java.lang.Math.max;
* for shorter reads, like single byte or bit reads. * for shorter reads, like single byte or bit reads.
*/ */
final class BufferedChannelImageInputStream extends ImageInputStreamImpl { final class BufferedChannelImageInputStream extends ImageInputStreamImpl {
private static final Closeable CLOSEABLE_STUB = new Closeable() {
@Override public void close() {}
};
static final int DEFAULT_BUFFER_SIZE = 8192; static final int DEFAULT_BUFFER_SIZE = 8192;
private ByteBuffer byteBuffer = ByteBuffer.allocate(DEFAULT_BUFFER_SIZE); private ByteBuffer byteBuffer = ByteBuffer.allocate(DEFAULT_BUFFER_SIZE);
@@ -63,6 +68,7 @@ final class BufferedChannelImageInputStream extends ImageInputStreamImpl {
private final byte[] integralCacheArray = integralCache.array(); private final byte[] integralCacheArray = integralCache.array();
private SeekableByteChannel channel; private SeekableByteChannel channel;
private Closeable closeable;
/** /**
* Constructs a {@code BufferedChannelImageInputStream} that will read from a given {@code File}. * Constructs a {@code BufferedChannelImageInputStream} that will read from a given {@code File}.
@@ -86,49 +92,62 @@ final class BufferedChannelImageInputStream extends ImageInputStreamImpl {
* @throws SecurityException if a security manager is installed, and it denies read access to the file. * @throws SecurityException if a security manager is installed, and it denies read access to the file.
*/ */
public BufferedChannelImageInputStream(final Path file) throws IOException { public BufferedChannelImageInputStream(final Path file) throws IOException {
this(FileChannel.open(notNull(file, "file"), StandardOpenOption.READ)); this(FileChannel.open(notNull(file, "file"), StandardOpenOption.READ), true);
} }
/** /**
* Constructs a {@code BufferedChannelImageInputStream} that will read from a given {@code RandomAccessFile}. * Constructs a {@code BufferedChannelImageInputStream} that will read from a given {@code RandomAccessFile}.
* <p>
* Closing this stream will close the {@code RandomAccessFile}.
* </p>
* *
* @param file a {@code RandomAccessFile} to read from. * @param file a {@code RandomAccessFile} to read from.
* @throws IllegalArgumentException if {@code file} is {@code null}. * @throws IllegalArgumentException if {@code file} is {@code null}.
*/ */
public BufferedChannelImageInputStream(final RandomAccessFile file) { public BufferedChannelImageInputStream(final RandomAccessFile file) {
// Assumption: Closing the FileChannel will also close its backing RandomAccessFile // Closing the RAF is inconsistent, but emulates the behavior of javax.imageio.stream.FileImageInputStream
// (it does in the OpenJDK implementation, and it makes sense, although I can't see this is documented behaviour). this(notNull(file, "file").getChannel(), true);
this(notNull(file, "file").getChannel());
} }
/** /**
* Constructs a {@code BufferedChannelImageInputStream} that will read from a given {@code FileInputStream}. * Constructs a {@code BufferedChannelImageInputStream} that will read from a given {@code FileInputStream}.
* <p> * <p>
* Closing this stream will close the {@code FileInputStream}. * Closing this stream will <em>not</em> close the {@code FileInputStream}.
* </p> * </p>
* *
* @param inputStream a {@code FileInputStream} to read from. * @param inputStream a {@code FileInputStream} to read from.
* @throws IllegalArgumentException if {@code inputStream} is {@code null}. * @throws IllegalArgumentException if {@code inputStream} is {@code null}.
*/ */
public BufferedChannelImageInputStream(final FileInputStream inputStream) { public BufferedChannelImageInputStream(final FileInputStream inputStream) {
// Assumption: Closing the FileChannel will also close its backing FileInputStream (it does in the OpenJDK implementation, although I can't see this is documented). this(notNull(inputStream, "inputStream").getChannel(), false);
this(notNull(inputStream, "inputStream").getChannel());
} }
/** /**
* Constructs a {@code BufferedChannelImageInputStream} that will read from a given {@code SeekableByteChannel}. * Constructs a {@code BufferedChannelImageInputStream} that will read from a given {@code SeekableByteChannel}.
* <p> * <p>
* Closing this stream will close the {@code SeekableByteChannel}. * Closing this stream will <em>not</em> close the {@code SeekableByteChannel}.
* </p> * </p>
* *
* @param channel a {@code SeekableByteChannel} to read from. * @param channel a {@code SeekableByteChannel} to read from.
* @throws IllegalArgumentException if {@code channel} is {@code null}. * @throws IllegalArgumentException if {@code channel} is {@code null}.
*/ */
public BufferedChannelImageInputStream(final SeekableByteChannel channel) { public BufferedChannelImageInputStream(final SeekableByteChannel channel) {
this(notNull(channel, "channel"), false);
}
/**
* Constructs a {@code BufferedChannelImageInputStream} that will read from a given {@code Cache}.
* <p>
* Closing this stream will close the {@code Cache}.
* </p>
*
* @param cache a {@code SeekableByteChannel} to read from.
* @throws IllegalArgumentException if {@code channel} is {@code null}.
*/
BufferedChannelImageInputStream(final Cache cache) {
this(notNull(cache, "cache"), true);
}
private BufferedChannelImageInputStream(final SeekableByteChannel channel, boolean closeChannelOnClose) {
this.channel = notNull(channel, "channel"); this.channel = notNull(channel, "channel");
this.closeable = closeChannelOnClose ? this.channel : CLOSEABLE_STUB;
} }
@SuppressWarnings("BooleanMethodIsAlwaysInverted") @SuppressWarnings("BooleanMethodIsAlwaysInverted")
@@ -246,8 +265,14 @@ final class BufferedChannelImageInputStream extends ImageInputStreamImpl {
buffer = null; buffer = null;
byteBuffer = null; byteBuffer = null;
channel.close();
channel = null; channel = null;
try {
closeable.close();
}
finally {
closeable = null;
}
} }
// Need to override the readShort(), readInt() and readLong() methods, // Need to override the readShort(), readInt() and readLong() methods,
@@ -315,9 +340,9 @@ final class BufferedChannelImageInputStream extends ImageInputStreamImpl {
public void flushBefore(final long pos) throws IOException { public void flushBefore(final long pos) throws IOException {
super.flushBefore(pos); super.flushBefore(pos);
if (channel instanceof MemoryCache) { if (channel instanceof Cache) {
// In case of memory cache, free up memory // In case of memory cache, free up memory
((MemoryCache) channel).flushBefore(pos); ((Cache) channel).flushBefore(pos);
} }
} }
} }
@@ -53,7 +53,7 @@ public final class BufferedInputStreamImageInputStreamSpi extends ImageInputStre
} }
// Otherwise, create a cache for backwards seeking // Otherwise, create a cache for backwards seeking
return new BufferedChannelImageInputStream(useCacheFile ? new DiskCache(channel, cacheDir): new MemoryCache(channel)); return new BufferedChannelImageInputStream(useCacheFile ? new FileCache(channel, cacheDir) : new MemoryCache(channel));
} }
throw new IllegalArgumentException("Expected input of type InputStream: " + input); throw new IllegalArgumentException("Expected input of type InputStream: " + input);
@@ -48,18 +48,18 @@ public final class ByteArrayImageInputStream extends ImageInputStreamImpl {
private final int dataOffset; private final int dataOffset;
private final int dataLength; private final int dataLength;
public ByteArrayImageInputStream(final byte[] pData) { public ByteArrayImageInputStream(final byte[] data) {
this(pData, 0, pData != null ? pData.length : -1); this(data, 0, data != null ? data.length : -1);
} }
public ByteArrayImageInputStream(final byte[] pData, int offset, int length) { public ByteArrayImageInputStream(final byte[] data, int offset, int length) {
data = notNull(pData, "data"); this.data = notNull(data, "data");
dataOffset = isBetween(0, pData.length, offset, "offset"); dataOffset = isMax(data.length, offset, "offset");
dataLength = isBetween(0, pData.length - offset, length, "length"); dataLength = isMax(data.length - offset, length, "length");
} }
private static int isBetween(final int low, final int high, final int value, final String name) { private static int isMax(final int high, final int value, final String name) {
return isTrue(value >= low && value <= high, value, String.format("%s out of range [%d, %d]: %d", name, low, high, value)); return isTrue(value >= 0 && value <= high, value, String.format("%s out of range [0, %d]: %d", name, high, value));
} }
public int read() throws IOException { public int read() throws IOException {
@@ -72,14 +72,14 @@ public final class ByteArrayImageInputStream extends ImageInputStreamImpl {
return data[((int) streamPos++) + dataOffset] & 0xff; return data[((int) streamPos++) + dataOffset] & 0xff;
} }
public int read(byte[] pBuffer, int pOffset, int pLength) throws IOException { public int read(byte[] buffer, int offset, int len) throws IOException {
if (streamPos >= dataLength) { if (streamPos >= dataLength) {
return -1; return -1;
} }
int length = (int) Math.min(this.dataLength - streamPos, pLength); int length = (int) Math.min(dataLength - streamPos, len);
bitOffset = 0; bitOffset = 0;
System.arraycopy(data, (int) streamPos + dataOffset, pBuffer, pOffset, length); System.arraycopy(data, (int) streamPos + dataOffset, buffer, offset, length);
streamPos += length; streamPos += length;
return length; return length;
@@ -0,0 +1,7 @@
package com.twelvemonkeys.imageio.stream;
import java.nio.channels.SeekableByteChannel;
interface Cache extends SeekableByteChannel {
void flushBefore(long pos);
}
@@ -26,19 +26,19 @@ import static java.nio.file.StandardOpenOption.WRITE;
// the usual {@link #read read} and {@link #write write} methods. From the // the usual {@link #read read} and {@link #write write} methods. From the
// standpoint of performance it is generally only worth mapping relatively // standpoint of performance it is generally only worth mapping relatively
// large files into memory. // large files into memory.
final class DiskCache implements SeekableByteChannel { final class FileCache implements Cache {
final static int BLOCK_SIZE = 1 << 13; final static int BLOCK_SIZE = 1 << 13;
private final FileChannel cache; private final FileChannel cache;
private final ReadableByteChannel channel; private final ReadableByteChannel channel;
// TODO: Perhaps skip this constructor? // TODO: Perhaps skip this constructor?
DiskCache(InputStream stream, File cacheDir) throws IOException { FileCache(InputStream stream, File cacheDir) throws IOException {
// Stream will be closed with channel, documented behavior // Stream will be closed with channel, documented behavior
this(Channels.newChannel(notNull(stream, "stream")), cacheDir); this(Channels.newChannel(notNull(stream, "stream")), cacheDir);
} }
public DiskCache(ReadableByteChannel channel, File cacheDir) throws IOException { public FileCache(ReadableByteChannel channel, File cacheDir) throws IOException {
this.channel = notNull(channel, "channel"); this.channel = notNull(channel, "channel");
isTrue(cacheDir == null || cacheDir.isDirectory(), cacheDir, "%s is not a directory"); isTrue(cacheDir == null || cacheDir.isDirectory(), cacheDir, "%s is not a directory");
@@ -65,12 +65,7 @@ final class DiskCache implements SeekableByteChannel {
@Override @Override
public void close() throws IOException { public void close() throws IOException {
try { cache.close();
cache.close();
}
finally {
channel.close();
}
} }
@Override @Override
@@ -110,5 +105,8 @@ final class DiskCache implements SeekableByteChannel {
public SeekableByteChannel truncate(long size) { public SeekableByteChannel truncate(long size) {
throw new NonWritableChannelException(); throw new NonWritableChannelException();
} }
@Override public void flushBefore(long pos) {
}
} }
@@ -13,12 +13,16 @@ import java.util.List;
import static com.twelvemonkeys.lang.Validate.notNull; import static com.twelvemonkeys.lang.Validate.notNull;
import static java.lang.Math.min; import static java.lang.Math.min;
public final class MemoryCache implements SeekableByteChannel { final class MemoryCache implements Cache {
final static int BLOCK_SIZE = 1 << 13; final static int BLOCK_SIZE = 1 << 13;
private static final byte[] NULL_BLOCK = new byte[0];
private final List<byte[]> cache = new ArrayList<>(); private final List<byte[]> cache = new ArrayList<>();
private final ReadableByteChannel channel; private final ReadableByteChannel channel;
private int maxBlock = Integer.MAX_VALUE;
private long length; private long length;
private long position; private long position;
private long start; private long start;
@@ -34,12 +38,14 @@ public final class MemoryCache implements SeekableByteChannel {
byte[] fetchBlock() throws IOException { byte[] fetchBlock() throws IOException {
long currPos = position; long currPos = position;
long index = currPos / BLOCK_SIZE; long index = currPos / BLOCK_SIZE;
if (index >= Integer.MAX_VALUE) { if (index >= Integer.MAX_VALUE) {
throw new IOException("Memory cache max size exceeded"); throw new IOException("Memory cache max size exceeded");
} }
if (index > maxBlock) {
return NULL_BLOCK;
}
while (index >= cache.size()) { while (index >= cache.size()) {
byte[] block; byte[] block;
@@ -51,7 +57,14 @@ public final class MemoryCache implements SeekableByteChannel {
} }
cache.add(block); cache.add(block);
length += readBlock(block); int bytesRead = readBlock(block);
length += bytesRead;
if (bytesRead < BLOCK_SIZE) {
// Last block, EOF found
maxBlock = (int) index;
return block;
}
} }
return cache.get((int) index); return cache.get((int) index);
@@ -63,7 +76,7 @@ public final class MemoryCache implements SeekableByteChannel {
while (wrapped.hasRemaining()) { while (wrapped.hasRemaining()) {
int count = channel.read(wrapped); int count = channel.read(wrapped);
if (count == -1) { if (count == -1) {
// Last block // Last block, EOF found
break; break;
} }
} }
@@ -78,23 +91,18 @@ public final class MemoryCache implements SeekableByteChannel {
@Override @Override
public void close() throws IOException { public void close() throws IOException {
try { cache.clear();
cache.clear();
}
finally {
channel.close();
}
} }
@Override @Override
public int read(ByteBuffer dest) throws IOException { public int read(ByteBuffer dest) throws IOException {
byte[] buffer = fetchBlock(); byte[] buffer = fetchBlock();
int bufferPos = (int) (position % BLOCK_SIZE);
if (position >= length) { if (position >= length) {
return -1; return -1;
} }
int bufferPos = (int) (position % BLOCK_SIZE);
int len = min(dest.remaining(), (int) min(BLOCK_SIZE - bufferPos, length - position)); int len = min(dest.remaining(), (int) min(BLOCK_SIZE - bufferPos, length - position));
dest.put(buffer, bufferPos, len); dest.put(buffer, bufferPos, len);
@@ -135,7 +143,8 @@ public final class MemoryCache implements SeekableByteChannel {
throw new NonWritableChannelException(); throw new NonWritableChannelException();
} }
void flushBefore(long pos) { @Override
public void flushBefore(long pos) {
if (pos < start) { if (pos < start) {
throw new IndexOutOfBoundsException("pos < flushed position"); throw new IndexOutOfBoundsException("pos < flushed position");
} }
@@ -53,20 +53,20 @@ public final class SubImageInputStream extends ImageInputStreamImpl {
/** /**
* Creates a {@link ImageInputStream}, reading up to a maximum number of bytes from the underlying stream. * Creates a {@link ImageInputStream}, reading up to a maximum number of bytes from the underlying stream.
* *
* @param pStream the underlying stream * @param stream the underlying stream
* @param pLength the maximum length to read from the stream. * @param length the maximum length to read from the stream.
* Note that {@code pStream} may contain less than this maximum number of bytes. * Note that {@code stream} may contain less than this maximum number of bytes.
* *
* @throws IOException if {@code pStream}'s position can't be determined. * @throws IOException if {@code stream}'s position can't be determined.
* @throws IllegalArgumentException if {@code pStream == null} or {@code pLength < 0} * @throws IllegalArgumentException if {@code stream == null} or {@code length < 0}
*/ */
public SubImageInputStream(final ImageInputStream pStream, final long pLength) throws IOException { public SubImageInputStream(final ImageInputStream stream, final long length) throws IOException {
Validate.notNull(pStream, "stream"); Validate.notNull(stream, "stream");
Validate.isTrue(pLength >= 0, pLength, "length < 0: %d"); Validate.isTrue(length >= 0, length, "length < 0: %d");
stream = pStream; this.stream = stream;
startPos = pStream.getStreamPosition(); this.startPos = stream.getStreamPosition();
length = pLength; this.length = length;
} }
public int read() throws IOException { public int read() throws IOException {
@@ -84,14 +84,14 @@ public final class SubImageInputStream extends ImageInputStreamImpl {
} }
} }
public int read(final byte[] pBytes, final int pOffset, final int pLength) throws IOException { public int read(final byte[] bytes, final int off, final int len) throws IOException {
if (streamPos >= length) { // Local EOF if (streamPos >= length) { // Local EOF
return -1; return -1;
} }
// Safe cast, as pLength can never cause int overflow // Safe cast, as len can never cause int overflow
int length = (int) Math.min(pLength, this.length - streamPos); int length = (int) Math.min(len, this.length - streamPos);
int count = stream.read(pBytes, pOffset, length); int count = stream.read(bytes, off, length);
if (count >= 0) { if (count >= 0) {
streamPos += count; streamPos += count;
@@ -113,18 +113,18 @@ public final class SubImageInputStream extends ImageInputStreamImpl {
} }
@Override @Override
public void seek(final long pPosition) throws IOException { public void seek(final long position) throws IOException {
if (pPosition < getFlushedPosition()) { if (position < getFlushedPosition()) {
throw new IndexOutOfBoundsException("pos < flushedPosition"); throw new IndexOutOfBoundsException("pos < flushedPosition");
} }
stream.seek(startPos + pPosition); stream.seek(startPos + position);
streamPos = pPosition; streamPos = position;
} }
@SuppressWarnings({"FinalizeDoesntCallSuperFinalize"}) @SuppressWarnings("MethodDoesntCallSuperMethod")
@Override @Override
protected void finalize() throws Throwable { protected void finalize() {
// Empty finalizer (for improved performance; no need to call super.finalize() in this case) // Empty finalizer (for improved performance; no need to call super.finalize() in this case)
} }
} }
@@ -80,7 +80,7 @@ public final class URLImageInputStreamSpi extends ImageInputStreamSpi {
// Otherwise revert to cached // Otherwise revert to cached
InputStream urlStream = url.openStream(); InputStream urlStream = url.openStream();
return new BufferedChannelImageInputStream(useCacheFile ? new DiskCache(urlStream, cacheDir) : new MemoryCache(urlStream)); return new BufferedChannelImageInputStream(useCacheFile ? new FileCache(urlStream, cacheDir) : new MemoryCache(urlStream));
} }
throw new IllegalArgumentException("Expected input of type URL: " + input); throw new IllegalArgumentException("Expected input of type URL: " + input);
@@ -257,18 +257,18 @@ public final class ImageTypeSpecifiers {
return createFromIndexColorModel(new IndexColorModel(bits, colors.length, colors, 0, hasAlpha, transIndex, dataType)); return createFromIndexColorModel(new IndexColorModel(bits, colors.length, colors, 0, hasAlpha, transIndex, dataType));
} }
public static ImageTypeSpecifier createFromIndexColorModel(final IndexColorModel pColorModel) { public static ImageTypeSpecifier createFromIndexColorModel(final IndexColorModel colorModel) {
return new IndexedImageTypeSpecifier(pColorModel); return new IndexedImageTypeSpecifier(colorModel);
} }
public static ImageTypeSpecifier createDiscreteAlphaIndexedFromIndexColorModel(final IndexColorModel pColorModel) { public static ImageTypeSpecifier createDiscreteAlphaIndexedFromIndexColorModel(final IndexColorModel colorModel) {
ColorModel colorModel = new DiscreteAlphaIndexColorModel(pColorModel); ColorModel discreteAlphaIndexColorModel = new DiscreteAlphaIndexColorModel(colorModel);
return new ImageTypeSpecifier(colorModel, colorModel.createCompatibleSampleModel(1, 1)); return new ImageTypeSpecifier(discreteAlphaIndexColorModel, discreteAlphaIndexColorModel.createCompatibleSampleModel(1, 1));
} }
public static ImageTypeSpecifier createDiscreteExtraSamplesIndexedFromIndexColorModel(final IndexColorModel pColorModel, int extraSamples, boolean hasAlpha) { public static ImageTypeSpecifier createDiscreteExtraSamplesIndexedFromIndexColorModel(final IndexColorModel colorModel, int extraSamples, boolean hasAlpha) {
ColorModel colorModel = new DiscreteAlphaIndexColorModel(pColorModel, extraSamples, hasAlpha); ColorModel discreteAlphaIndexColorModel = new DiscreteAlphaIndexColorModel(colorModel, extraSamples, hasAlpha);
return new ImageTypeSpecifier(colorModel, colorModel.createCompatibleSampleModel(1, 1)); return new ImageTypeSpecifier(discreteAlphaIndexColorModel, discreteAlphaIndexColorModel.createCompatibleSampleModel(1, 1));
} }
public static ImageTypeSpecifier createFromRenderedImage(RenderedImage image) { public static ImageTypeSpecifier createFromRenderedImage(RenderedImage image) {
@@ -279,7 +279,9 @@ public final class ImageTypeSpecifiers {
if (image instanceof BufferedImage) { if (image instanceof BufferedImage) {
int bufferedImageType = ((BufferedImage) image).getType(); int bufferedImageType = ((BufferedImage) image).getType();
if (bufferedImageType != BufferedImage.TYPE_CUSTOM) { 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) {
return createFromBufferedImageType(bufferedImageType); return createFromBufferedImageType(bufferedImageType);
} }
} }
@@ -52,12 +52,12 @@ final class IndexedImageTypeSpecifier extends ImageTypeSpecifier {
} }
@Override @Override
public final BufferedImage createBufferedImage(final int pWidth, final int pHeight) { public BufferedImage createBufferedImage(final int width, final int height) {
try { try {
// This is a fix for the super-method, that first creates a sample model, and then // 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 // 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. // that approach, is that it always creates a TYPE_CUSTOM BufferedImage for indexed images.
WritableRaster raster = colorModel.createCompatibleWritableRaster(pWidth, pHeight); WritableRaster raster = colorModel.createCompatibleWritableRaster(width, height);
return new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null); return new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);
} }
catch (NegativeArraySizeException e) { catch (NegativeArraySizeException e) {
@@ -17,6 +17,7 @@ import java.util.Arrays;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
@@ -170,7 +171,7 @@ public class StandardImageMetadataSupportTest {
@Test @Test
public void withTextValuesMap() { public void withTextValuesMap() {
Map<String, String> entries = new HashMap<>(); Map<String, String> entries = new LinkedHashMap<>();
entries.put("foo", "bar"); entries.put("foo", "bar");
entries.put("bar", "xyzzy"); entries.put("bar", "xyzzy");
@@ -36,9 +36,11 @@ import java.awt.color.ColorSpace;
import java.awt.color.ICC_ColorSpace; import java.awt.color.ICC_ColorSpace;
import java.awt.color.ICC_Profile; import java.awt.color.ICC_Profile;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Arrays; import java.util.Arrays;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assume.assumeFalse;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
public class KCMSSanitizerStrategyTest { public class KCMSSanitizerStrategyTest {
@@ -56,6 +58,8 @@ public class KCMSSanitizerStrategyTest {
@Test @Test
public void testFixProfileUpdateHeader() throws Exception { public void testFixProfileUpdateHeader() throws Exception {
assumeICC_ProfileNotSealed(); // Ignores test for JDK 19+
byte[] header = new byte[128]; byte[] header = new byte[128];
header[ICC_Profile.icHdrRenderingIntent + 3] = 1; header[ICC_Profile.icHdrRenderingIntent + 3] = 1;
ICC_Profile profile = mock(ICC_Profile.class); ICC_Profile profile = mock(ICC_Profile.class);
@@ -69,6 +73,17 @@ public class KCMSSanitizerStrategyTest {
verify(profile).setData(eq(ICC_Profile.icSigHead), any(byte[].class)); verify(profile).setData(eq(ICC_Profile.icSigHead), any(byte[].class));
} }
static void assumeICC_ProfileNotSealed() {
try {
Method isSealed = Class.class.getMethod("isSealed");
Boolean result = (Boolean) isSealed.invoke(ICC_Profile.class);
assumeFalse("Can't mock ICC_Profile, class is sealed (as of JDK 19).", result);
}
catch (ReflectiveOperationException ignore) {
// We can't have sealed classes if we don't have the isSealed method...
}
}
@Test @Test
public void testFixProfileCorbisRGB() throws IOException { public void testFixProfileCorbisRGB() throws IOException {
// TODO: Consider re-writing this using mocks, to avoid dependencies on the CMS implementation // TODO: Consider re-writing this using mocks, to avoid dependencies on the CMS implementation
@@ -34,6 +34,7 @@ import org.junit.Test;
import java.awt.color.ICC_Profile; import java.awt.color.ICC_Profile;
import static com.twelvemonkeys.imageio.color.KCMSSanitizerStrategyTest.assumeICC_ProfileNotSealed;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -46,6 +47,8 @@ public class LCMSSanitizerStrategyTest {
@Test @Test
public void testFixProfile() throws Exception { public void testFixProfile() throws Exception {
assumeICC_ProfileNotSealed(); // Ignores test for JDK 19+
ICC_Profile profile = mock(ICC_Profile.class); ICC_Profile profile = mock(ICC_Profile.class);
new LCMSSanitizerStrategy().fixProfile(profile); new LCMSSanitizerStrategy().fixProfile(profile);
@@ -57,7 +57,7 @@ import static org.mockito.Mockito.verify;
* @version $Id: BufferedFileImageInputStreamTestCase.java,v 1.0 Apr 21, 2009 10:58:48 AM haraldk Exp$ * @version $Id: BufferedFileImageInputStreamTestCase.java,v 1.0 Apr 21, 2009 10:58:48 AM haraldk Exp$
*/ */
// TODO: Remove this test, and instead test the disk cache directly! // TODO: Remove this test, and instead test the disk cache directly!
public class BufferedChannelImageInputStreamDiskCacheTest { public class BufferedChannelImageInputStreamFileCacheTest {
private final Random random = new Random(170984354357234566L); private final Random random = new Random(170984354357234566L);
private InputStream randomDataToInputStream(byte[] data) { private InputStream randomDataToInputStream(byte[] data) {
@@ -68,7 +68,7 @@ public class BufferedChannelImageInputStreamDiskCacheTest {
@Test @Test
public void testCreate() throws IOException { public void testCreate() throws IOException {
try (BufferedChannelImageInputStream stream = new BufferedChannelImageInputStream(new DiskCache(new ByteArrayInputStream(new byte[0]), null))) { try (BufferedChannelImageInputStream stream = new BufferedChannelImageInputStream(new FileCache(new ByteArrayInputStream(new byte[0]), null))) {
assertEquals("Stream length should be unknown", -1, stream.length()); assertEquals("Stream length should be unknown", -1, stream.length());
} }
} }
@@ -76,7 +76,7 @@ public class BufferedChannelImageInputStreamDiskCacheTest {
@Test @Test
public void testCreateNullStream() throws IOException { public void testCreateNullStream() throws IOException {
try { try {
new DiskCache((InputStream) null, null); new FileCache((InputStream) null, null);
fail("Expected IllegalArgumentException"); fail("Expected IllegalArgumentException");
} }
catch (IllegalArgumentException expected) { catch (IllegalArgumentException expected) {
@@ -90,7 +90,7 @@ public class BufferedChannelImageInputStreamDiskCacheTest {
@Test @Test
public void testCreateNullChannel() throws IOException { public void testCreateNullChannel() throws IOException {
try { try {
new DiskCache((ReadableByteChannel) null, null); new FileCache((ReadableByteChannel) null, null);
fail("Expected IllegalArgumentException"); fail("Expected IllegalArgumentException");
} }
catch (IllegalArgumentException expected) { catch (IllegalArgumentException expected) {
@@ -106,7 +106,7 @@ public class BufferedChannelImageInputStreamDiskCacheTest {
byte[] data = new byte[1024 * 1024]; byte[] data = new byte[1024 * 1024];
InputStream input = randomDataToInputStream(data); InputStream input = randomDataToInputStream(data);
try (BufferedChannelImageInputStream stream = new BufferedChannelImageInputStream(new DiskCache(input, null))) { try (BufferedChannelImageInputStream stream = new BufferedChannelImageInputStream(new FileCache(input, null))) {
assertEquals("Stream length should be unknown", -1, stream.length()); assertEquals("Stream length should be unknown", -1, stream.length());
for (byte value : data) { for (byte value : data) {
@@ -122,7 +122,7 @@ public class BufferedChannelImageInputStreamDiskCacheTest {
byte[] data = new byte[1024 * 1024]; byte[] data = new byte[1024 * 1024];
InputStream input = randomDataToInputStream(data); InputStream input = randomDataToInputStream(data);
try (BufferedChannelImageInputStream stream = new BufferedChannelImageInputStream(new DiskCache(input, null))) { try (BufferedChannelImageInputStream stream = new BufferedChannelImageInputStream(new FileCache(input, null))) {
assertEquals("Stream length should be unknown", -1, stream.length()); assertEquals("Stream length should be unknown", -1, stream.length());
byte[] result = new byte[1024]; byte[] result = new byte[1024];
@@ -141,7 +141,7 @@ public class BufferedChannelImageInputStreamDiskCacheTest {
byte[] data = new byte[1024 * 14]; byte[] data = new byte[1024 * 14];
InputStream input = randomDataToInputStream(data); InputStream input = randomDataToInputStream(data);
try (BufferedChannelImageInputStream stream = new BufferedChannelImageInputStream(new DiskCache(input, null))) { try (BufferedChannelImageInputStream stream = new BufferedChannelImageInputStream(new FileCache(input, null))) {
assertEquals("Stream length should be unknown", -1, stream.length()); assertEquals("Stream length should be unknown", -1, stream.length());
byte[] result = new byte[7]; byte[] result = new byte[7];
@@ -159,7 +159,7 @@ public class BufferedChannelImageInputStreamDiskCacheTest {
byte[] data = new byte[1024 * 18]; byte[] data = new byte[1024 * 18];
InputStream input = randomDataToInputStream(data); InputStream input = randomDataToInputStream(data);
try (BufferedChannelImageInputStream stream = new BufferedChannelImageInputStream(new DiskCache(input, null))) { try (BufferedChannelImageInputStream stream = new BufferedChannelImageInputStream(new FileCache(input, null))) {
assertEquals("Stream length should be unknown", -1, stream.length()); assertEquals("Stream length should be unknown", -1, stream.length());
byte[] result = new byte[9]; byte[] result = new byte[9];
@@ -180,7 +180,7 @@ public class BufferedChannelImageInputStreamDiskCacheTest {
byte[] data = new byte[256]; byte[] data = new byte[256];
InputStream input = randomDataToInputStream(data); InputStream input = randomDataToInputStream(data);
try (BufferedChannelImageInputStream stream = new BufferedChannelImageInputStream(new DiskCache(input, null))) { try (BufferedChannelImageInputStream stream = new BufferedChannelImageInputStream(new FileCache(input, null))) {
assertEquals("Stream length should be unknown", -1, stream.length()); assertEquals("Stream length should be unknown", -1, stream.length());
byte[] buffer = new byte[data.length * 2]; byte[] buffer = new byte[data.length * 2];
@@ -198,7 +198,7 @@ public class BufferedChannelImageInputStreamDiskCacheTest {
long value = ByteBuffer.wrap(bytes).getLong(); long value = ByteBuffer.wrap(bytes).getLong();
// Create stream // Create stream
try (ImageInputStream stream = new BufferedChannelImageInputStream(new DiskCache(input, null))) { try (ImageInputStream stream = new BufferedChannelImageInputStream(new FileCache(input, null))) {
for (int i = 1; i <= 64; i++) { for (int i = 1; i <= 64; i++) {
assertEquals(String.format("bit %d differ", i), (value << (i - 1L)) >>> 63L, stream.readBit()); assertEquals(String.format("bit %d differ", i), (value << (i - 1L)) >>> 63L, stream.readBit());
} }
@@ -212,7 +212,7 @@ public class BufferedChannelImageInputStreamDiskCacheTest {
long value = ByteBuffer.wrap(bytes).getLong(); long value = ByteBuffer.wrap(bytes).getLong();
// Create stream // Create stream
try (ImageInputStream stream = new BufferedChannelImageInputStream(new DiskCache(input, null))) { try (ImageInputStream stream = new BufferedChannelImageInputStream(new FileCache(input, null))) {
for (int i = 1; i <= 64; i++) { for (int i = 1; i <= 64; i++) {
stream.seek(0); stream.seek(0);
assertEquals(String.format("bit %d differ", i), value >>> (64L - i), stream.readBits(i)); assertEquals(String.format("bit %d differ", i), value >>> (64L - i), stream.readBits(i));
@@ -228,7 +228,7 @@ public class BufferedChannelImageInputStreamDiskCacheTest {
long value = ByteBuffer.wrap(bytes).getLong(); long value = ByteBuffer.wrap(bytes).getLong();
// Create stream // Create stream
try (ImageInputStream stream = new BufferedChannelImageInputStream(new DiskCache(input, null))) { try (ImageInputStream stream = new BufferedChannelImageInputStream(new FileCache(input, null))) {
for (int i = 1; i <= 60; i++) { for (int i = 1; i <= 60; i++) {
stream.seek(0); stream.seek(0);
stream.setBitOffset(i % 8); stream.setBitOffset(i % 8);
@@ -244,7 +244,7 @@ public class BufferedChannelImageInputStreamDiskCacheTest {
InputStream input = randomDataToInputStream(bytes); InputStream input = randomDataToInputStream(bytes);
ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN); ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
try (final ImageInputStream stream = new BufferedChannelImageInputStream(new DiskCache(input, null))) { try (final ImageInputStream stream = new BufferedChannelImageInputStream(new FileCache(input, null))) {
stream.setByteOrder(ByteOrder.BIG_ENDIAN); stream.setByteOrder(ByteOrder.BIG_ENDIAN);
for (int i = 0; i < bytes.length / 2; i++) { for (int i = 0; i < bytes.length / 2; i++) {
@@ -282,7 +282,7 @@ public class BufferedChannelImageInputStreamDiskCacheTest {
InputStream input = randomDataToInputStream(bytes); InputStream input = randomDataToInputStream(bytes);
ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN); ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
try (final ImageInputStream stream = new BufferedChannelImageInputStream(new DiskCache(input, null))) { try (final ImageInputStream stream = new BufferedChannelImageInputStream(new FileCache(input, null))) {
stream.setByteOrder(ByteOrder.BIG_ENDIAN); stream.setByteOrder(ByteOrder.BIG_ENDIAN);
for (int i = 0; i < bytes.length / 4; i++) { for (int i = 0; i < bytes.length / 4; i++) {
@@ -320,7 +320,7 @@ public class BufferedChannelImageInputStreamDiskCacheTest {
InputStream input = randomDataToInputStream(bytes); InputStream input = randomDataToInputStream(bytes);
ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN); ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN);
try (final ImageInputStream stream = new BufferedChannelImageInputStream(new DiskCache(input, null))) { try (final ImageInputStream stream = new BufferedChannelImageInputStream(new FileCache(input, null))) {
stream.setByteOrder(ByteOrder.BIG_ENDIAN); stream.setByteOrder(ByteOrder.BIG_ENDIAN);
for (int i = 0; i < bytes.length / 8; i++) { for (int i = 0; i < bytes.length / 8; i++) {
@@ -357,7 +357,7 @@ public class BufferedChannelImageInputStreamDiskCacheTest {
byte[] bytes = new byte[9]; byte[] bytes = new byte[9];
InputStream input = randomDataToInputStream(bytes); InputStream input = randomDataToInputStream(bytes);
try (final ImageInputStream stream = new BufferedChannelImageInputStream(new DiskCache(input, null))) { try (final ImageInputStream stream = new BufferedChannelImageInputStream(new FileCache(input, null))) {
stream.seek(1000); stream.seek(1000);
assertEquals(-1, stream.read()); assertEquals(-1, stream.read());
@@ -406,11 +406,11 @@ public class BufferedChannelImageInputStreamDiskCacheTest {
@Test @Test
public void testClose() throws IOException { public void testClose() throws IOException {
// Create wrapper stream // Create wrapper stream
InputStream mock = mock(InputStream.class); Cache cache = mock(Cache.class);
ImageInputStream stream = new BufferedChannelImageInputStream(new DiskCache(mock, null)); ImageInputStream stream = new BufferedChannelImageInputStream(cache);
stream.close(); stream.close();
verify(mock, only()).close(); verify(cache, only()).close();
} }
@Test @Test
@@ -422,7 +422,7 @@ public class BufferedChannelImageInputStreamDiskCacheTest {
byte[] bytes = new byte[size]; byte[] bytes = new byte[size];
InputStream input = randomDataToInputStream(bytes); InputStream input = randomDataToInputStream(bytes);
try (BufferedChannelImageInputStream stream = new BufferedChannelImageInputStream(new DiskCache(input, null))) { try (BufferedChannelImageInputStream stream = new BufferedChannelImageInputStream(new FileCache(input, null))) {
byte[] result = new byte[size]; byte[] result = new byte[size];
int head = stream.read(result, 0, 12); // Provoke a buffered read int head = stream.read(result, 0, 12); // Provoke a buffered read
int len = stream.read(result, 12, size - 12); // Rest of buffer + direct read int len = stream.read(result, 12, size - 12); // Rest of buffer + direct read
@@ -402,15 +402,33 @@ public class BufferedChannelImageInputStreamMemoryCacheTest {
assertEquals(-1, stream.read()); assertEquals(-1, stream.read());
} }
} }
@Test
public void testSeekWayPastEOFShouldNotThrowOOME() throws IOException {
byte[] bytes = new byte[9];
InputStream input = randomDataToInputStream(bytes);
try (final ImageInputStream stream = new BufferedChannelImageInputStream(new MemoryCache(input))) {
stream.seek(Integer.MAX_VALUE * 4L * 512L); // ~4 TB
assertEquals(-1, stream.read()); // No OOME should happen...
stream.seek(0);
for (byte value : bytes) {
assertEquals(value, stream.readByte());
}
assertEquals(-1, stream.read());
}
}
@Test @Test
public void testClose() throws IOException { public void testClose() throws IOException {
// Create wrapper stream // Create wrapper stream
InputStream mock = mock(InputStream.class); Cache cache = mock(Cache.class);
ImageInputStream stream = new BufferedChannelImageInputStream(new MemoryCache(mock)); ImageInputStream stream = new BufferedChannelImageInputStream(cache);
stream.close(); stream.close();
verify(mock, only()).close(); verify(cache, only()).close();
} }
@Test @Test
@@ -47,7 +47,7 @@ import java.util.Random;
import static com.twelvemonkeys.imageio.stream.BufferedImageInputStreamTest.rangeEquals; import static com.twelvemonkeys.imageio.stream.BufferedImageInputStreamTest.rangeEquals;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.only; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
/** /**
@@ -403,14 +403,11 @@ public class BufferedChannelImageInputStreamTest {
@Test @Test
public void testCloseChannel() throws IOException { public void testCloseChannel() throws IOException {
// NOTE: As the stream-based constructor is chained to the channel-based one, SeekableByteChannel channel = mock(SeekableByteChannel.class);
// we'll rely on the fact that closing the channel will close the stream. ImageInputStream stream = new BufferedChannelImageInputStream(channel);
SeekableByteChannel mock = mock(SeekableByteChannel.class);
ImageInputStream stream = new BufferedChannelImageInputStream(mock);
stream.close(); stream.close();
verify(mock, only()).close(); verify(channel, never()).close();
} }
@Test @Test
@@ -31,6 +31,7 @@
package com.twelvemonkeys.imageio.util; package com.twelvemonkeys.imageio.util;
import com.twelvemonkeys.imageio.stream.URLImageInputStreamSpi; import com.twelvemonkeys.imageio.stream.URLImageInputStreamSpi;
import com.twelvemonkeys.lang.Validate;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
@@ -38,14 +39,18 @@ import org.mockito.InOrder;
import org.mockito.invocation.InvocationOnMock; import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer; import org.mockito.stubbing.Answer;
import javax.imageio.*; import javax.imageio.IIOException;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.event.IIOReadProgressListener; import javax.imageio.event.IIOReadProgressListener;
import javax.imageio.metadata.IIOMetadata; import javax.imageio.metadata.IIOMetadata;
import javax.imageio.spi.IIORegistry; import javax.imageio.spi.IIORegistry;
import javax.imageio.spi.ImageReaderSpi; import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.ImageInputStream;
import java.awt.*; import java.awt.*;
import java.awt.geom.AffineTransform; import java.awt.geom.*;
import java.awt.image.*; import java.awt.image.*;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@@ -53,6 +58,7 @@ import java.lang.reflect.ParameterizedType;
import java.net.URL; import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@@ -602,7 +608,7 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
assertReadWithSourceRegionParamEqualImage(new Rectangle(3, 3, 9, 9), getTestData().get(0), 0); assertReadWithSourceRegionParamEqualImage(new Rectangle(3, 3, 9, 9), getTestData().get(0), 0);
} }
protected void assertReadWithSourceRegionParamEqualImage(final Rectangle r, final TestData data, final int imageIndex) throws IOException { protected void assertReadWithSourceRegionParamEqualImage(final Rectangle r, final TestData data, @SuppressWarnings("SameParameterValue") final int imageIndex) throws IOException {
ImageReader reader = createReader(); ImageReader reader = createReader();
try (ImageInputStream inputStream = data.getInputStream()) { try (ImageInputStream inputStream = data.getInputStream()) {
reader.setInput(inputStream); reader.setInput(inputStream);
@@ -1828,52 +1834,51 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
private final List<Dimension> sizes; private final List<Dimension> sizes;
private final List<BufferedImage> images; private final List<BufferedImage> images;
public TestData(final Object pInput, final Dimension... pSizes) { public TestData(final Object input, final Dimension... dimensions) {
this(pInput, Arrays.asList(pSizes), null); this(input, Arrays.asList(dimensions), null);
} }
public TestData(final Object pInput, final BufferedImage... pImages) { public TestData(final Object input, final BufferedImage... images) {
this(pInput, null, Arrays.asList(pImages)); this(input, null, Arrays.asList(images));
} }
public TestData(final Object pInput, final List<Dimension> pSizes, final List<BufferedImage> pImages) { public TestData(final Object input, final List<Dimension> dimensions, final List<BufferedImage> images) {
if (pInput == null) { Validate.notNull(input, "input");
throw new IllegalArgumentException("input == null"); Validate.isTrue(dimensions != null || images != null, "Need either dimensions or image");
}
sizes = new ArrayList<>(); List<Dimension> combinedDimensions;
images = new ArrayList<>(); if (dimensions == null) {
// Copy dimensions from images
combinedDimensions = new ArrayList<>(images.size());
List<Dimension> sizes = pSizes; for (BufferedImage image : images) {
if (sizes == null) { combinedDimensions.add(new Dimension(image.getWidth(), image.getHeight()));
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) { else {
if (pImages.size() != pSizes.size()) { // Validate equal dimensions
throw new IllegalArgumentException("Size parameter and image size differs"); if (images != null) {
} if (images.size() != dimensions.size()) {
for (int i = 0; i < sizes.size(); i++) { throw new IllegalArgumentException("Dimensions and images parameter's size differs");
if (!new Dimension(pImages.get(i).getWidth(), pImages.get(i).getHeight()).equals(sizes.get(i))) {
throw new IllegalArgumentException("Size parameter and image 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);
} }
this.sizes.addAll(sizes); this.sizes = Collections.unmodifiableList(combinedDimensions);
if (pImages != null) {
images.addAll(pImages);
}
input = pInput; this.images = images != null
? Collections.unmodifiableList(new ArrayList<>(images))
: Collections.<BufferedImage>emptyList();
this.input = input;
} }
public Object getInput() { public Object getInput() {
@@ -1898,13 +1903,13 @@ public abstract class ImageReaderAbstractTest<T extends ImageReader> {
return sizes.size(); return sizes.size();
} }
public Dimension getDimension(final int pIndex) { public Dimension getDimension(final int index) {
return sizes.get(pIndex); return sizes.get(index);
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
public BufferedImage getImage(final int pIndex) { public BufferedImage getImage(final int index) {
return images.get(pIndex); return images.get(index);
} }
@Override @Override
@@ -39,6 +39,7 @@ import java.awt.color.*;
import java.awt.image.*; import java.awt.image.*;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
public class ImageTypeSpecifiersTest { public class ImageTypeSpecifiersTest {
@@ -736,6 +737,7 @@ public class ImageTypeSpecifiersTest {
ImageTypeSpecifier fromType = ImageTypeSpecifiers.createFromBufferedImageType(type); ImageTypeSpecifier fromType = ImageTypeSpecifiers.createFromBufferedImageType(type);
assertEquals(fromConstructor.getColorModel(), fromType.getColorModel()); assertEquals(fromConstructor.getColorModel(), fromType.getColorModel());
assertEquals(fromConstructor.getSampleModel(), fromType.getSampleModel());
} }
} }
@@ -747,13 +749,43 @@ public class ImageTypeSpecifiersTest {
ImageTypeSpecifier fromImage = ImageTypeSpecifiers.createFromRenderedImage(image); ImageTypeSpecifier fromImage = ImageTypeSpecifiers.createFromRenderedImage(image);
assertEquals(fromConstructor.getColorModel(), fromImage.getColorModel()); 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) { private static byte[] createByteLut(final int count) {
byte[] lut = new byte[count]; byte[] lut = new byte[count];
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
lut[i] = (byte) count; lut[i] = (byte) (i * 255 / count);
} }
return lut; return lut;
} }
@@ -762,7 +794,8 @@ public class ImageTypeSpecifiersTest {
int[] lut = new int[count]; int[] lut = new int[count];
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
lut[i] = 0xff000000 | count << 16 | count << 8 | count; int val = (i * 255 / count);
lut[i] = 0xff000000 | val << 16 | val << 8 | val;
} }
return lut; return lut;
@@ -43,15 +43,17 @@ import javax.imageio.spi.IIORegistry;
import javax.imageio.spi.ImageWriterSpi; import javax.imageio.spi.ImageWriterSpi;
import javax.imageio.stream.ImageOutputStream; import javax.imageio.stream.ImageOutputStream;
import java.awt.*; import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.*;
import java.awt.image.RenderedImage;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.net.URL; import java.net.URL;
import java.util.List; import java.util.List;
import static org.junit.Assert.*; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
/** /**
@@ -108,8 +110,8 @@ public abstract class ImageWriterAbstractTest<T extends ImageWriter> {
return getTestData().get(index); return getTestData().get(index);
} }
protected URL getClassLoaderResource(final String pName) { protected URL getClassLoaderResource(final String name) {
return getClass().getResource(pName); return getClass().getResource(name);
} }
@Test @Test
+18 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.9.0</version> <version>3.10.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-hdr</artifactId> <artifactId>imageio-hdr</artifactId>
<name>TwelveMonkeys :: ImageIO :: HDR plugin</name> <name>TwelveMonkeys :: ImageIO :: HDR plugin</name>
@@ -32,4 +32,21 @@
<artifactId>imageio-metadata</artifactId> <artifactId>imageio-metadata</artifactId>
</dependency> </dependency>
</dependencies> </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> </project>
@@ -59,7 +59,7 @@ public final class HDRImageReader extends ImageReaderBase {
private HDRHeader header; private HDRHeader header;
protected HDRImageReader(final ImageReaderSpi provider) { HDRImageReader(final ImageReaderSpi provider) {
super(provider); super(provider);
} }
@@ -196,7 +196,7 @@ public final class HDRImageReader extends ImageReaderBase {
int ySub = param != null ? param.getSourceYSubsampling() : 1; int ySub = param != null ? param.getSourceYSubsampling() : 1;
byte[] rowRGBE = new byte[width * 4]; byte[] rowRGBE = new byte[width * 4];
byte[] pixelRGBE = new byte[width]; byte[] pixelRGBE = new byte[4];
processImageStarted(imageIndex); processImageStarted(imageIndex);
@@ -231,7 +231,7 @@ public final class HDRImageReader extends ImageReaderBase {
processImageComplete(); processImageComplete();
return destination.getRaster(); return raster;
} }
@Override @Override
@@ -5,7 +5,7 @@ import com.twelvemonkeys.imageio.StandardImageMetadataSupport;
import javax.imageio.ImageTypeSpecifier; import javax.imageio.ImageTypeSpecifier;
import javax.imageio.metadata.IIOMetadataNode; import javax.imageio.metadata.IIOMetadataNode;
public class HDRMetadata extends StandardImageMetadataSupport { final class HDRMetadata extends StandardImageMetadataSupport {
public HDRMetadata(ImageTypeSpecifier type, HDRHeader header) { public HDRMetadata(ImageTypeSpecifier type, HDRHeader header) {
super(builder(type) super(builder(type)
.withCompressionTypeName("RLE") .withCompressionTypeName("RLE")
+20 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.9.0</version> <version>3.10.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-icns</artifactId> <artifactId>imageio-icns</artifactId>
<name>TwelveMonkeys :: ImageIO :: ICNS plugin</name> <name>TwelveMonkeys :: ImageIO :: ICNS plugin</name>
@@ -26,4 +26,23 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </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> </project>
+20 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.9.0</version> <version>3.10.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-iff</artifactId> <artifactId>imageio-iff</artifactId>
<name>TwelveMonkeys :: ImageIO :: IFF plugin</name> <name>TwelveMonkeys :: ImageIO :: IFF plugin</name>
@@ -29,4 +29,23 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </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> </project>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.9.0</version> <version>3.10.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-jpeg-jai-interop</artifactId> <artifactId>imageio-jpeg-jai-interop</artifactId>
<name>TwelveMonkeys :: ImageIO :: JPEG/JAI TIFF Interop</name> <name>TwelveMonkeys :: ImageIO :: JPEG/JAI TIFF Interop</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.9.0</version> <version>3.10.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-jpeg-jep262-interop</artifactId> <artifactId>imageio-jpeg-jep262-interop</artifactId>
<name>TwelveMonkeys :: ImageIO :: JPEG/JEP-262 Interop</name> <name>TwelveMonkeys :: ImageIO :: JPEG/JEP-262 Interop</name>
+20 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.9.0</version> <version>3.10.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-jpeg</artifactId> <artifactId>imageio-jpeg</artifactId>
<name>TwelveMonkeys :: ImageIO :: JPEG plugin</name> <name>TwelveMonkeys :: ImageIO :: JPEG plugin</name>
@@ -32,4 +32,23 @@
<artifactId>imageio-metadata</artifactId> <artifactId>imageio-metadata</artifactId>
</dependency> </dependency>
</dependencies> </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> </project>
@@ -145,8 +145,8 @@ final class HuffmanTable extends Segment {
} }
int c = temp >> 4; int c = temp >> 4;
if (c > 2) { if (c > 1) {
throw new IIOException("Unexpected JPEG Huffman Table class (> 2): " + c); throw new IIOException("Unexpected JPEG Huffman Table class (> 1): " + c);
} }
table.tc[t][c] = true; table.tc[t][c] = true;
@@ -888,20 +888,21 @@ public final class JPEGImageReader extends ImageReaderBase {
throw new IIOException("No SOF segment in stream"); throw new IIOException("No SOF segment in stream");
} }
private Application lastAppSegment(int marker, String identifier) throws IOException {
List<Application> appSegments = getAppSegments(marker, identifier);
return appSegments.isEmpty() ? null : appSegments.get(appSegments.size() - 1);
}
AdobeDCT getAdobeDCT() throws IOException { AdobeDCT getAdobeDCT() throws IOException {
List<Application> adobe = getAppSegments(JPEG.APP14, "Adobe"); return (AdobeDCT) lastAppSegment(JPEG.APP14, "Adobe");
return adobe.isEmpty() ? null : (AdobeDCT) adobe.get(0);
} }
JFIF getJFIF() throws IOException{ JFIF getJFIF() throws IOException{
List<Application> jfif = getAppSegments(JPEG.APP0, "JFIF"); return (JFIF) lastAppSegment(JPEG.APP0, "JFIF");
return jfif.isEmpty() ? null : (JFIF) jfif.get(0);
} }
JFXX getJFXX() throws IOException { JFXX getJFXX() throws IOException {
List<Application> jfxx = getAppSegments(JPEG.APP0, "JFXX"); return (JFXX) lastAppSegment(JPEG.APP0, "JFXX");
return jfxx.isEmpty() ? null : (JFXX) jfxx.get(0);
} }
private EXIF getExif() throws IOException { private EXIF getExif() throws IOException {
@@ -52,7 +52,7 @@ import static com.twelvemonkeys.imageio.util.IIOUtil.lookupProviderByName;
* @version $Id: JPEGImageReaderSpi.java,v 1.0 24.01.11 22.12 haraldk Exp$ * @version $Id: JPEGImageReaderSpi.java,v 1.0 24.01.11 22.12 haraldk Exp$
*/ */
public final class JPEGImageReaderSpi extends ImageReaderSpiBase { public final class JPEGImageReaderSpi extends ImageReaderSpiBase {
protected ImageReaderSpi delegateProvider; ImageReaderSpi delegateProvider;
/** /**
* Constructor for use by {@link javax.imageio.spi.IIORegistry} only. * Constructor for use by {@link javax.imageio.spi.IIORegistry} only.
@@ -32,19 +32,21 @@ package com.twelvemonkeys.imageio.plugins.jpeg;
import com.twelvemonkeys.imageio.ImageWriterBase; import com.twelvemonkeys.imageio.ImageWriterBase;
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG; import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
import com.twelvemonkeys.imageio.util.ProgressListenerBase; import com.twelvemonkeys.imageio.util.ProgressListenerBase;
import org.w3c.dom.NodeList;
import javax.imageio.IIOImage; import javax.imageio.IIOImage;
import javax.imageio.ImageTypeSpecifier; import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter; import javax.imageio.ImageWriter;
import javax.imageio.event.IIOWriteWarningListener; import javax.imageio.event.IIOWriteWarningListener;
import javax.imageio.metadata.IIOInvalidTreeException;
import javax.imageio.metadata.IIOMetadata; import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode; import javax.imageio.metadata.IIOMetadataNode;
import java.awt.*; import java.awt.*;
import java.awt.color.ColorSpace; import java.awt.color.*;
import java.awt.color.ICC_ColorSpace;
import java.awt.color.ICC_Profile;
import java.awt.image.*; import java.awt.image.*;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@@ -161,7 +163,7 @@ public final class JPEGImageWriter extends ImageWriterBase {
else { else {
// If the image metadata is our substitute, convert it back to native com.sun format // If the image metadata is our substitute, convert it back to native com.sun format
if (image.getMetadata() instanceof JPEGImage10Metadata) { if (image.getMetadata() instanceof JPEGImage10Metadata) {
ImageTypeSpecifier type = image.hasRaster() ? null : ImageTypeSpecifier.createFromRenderedImage(image.getRenderedImage()); ImageTypeSpecifier type = image.hasRaster() ? null : ImageTypeSpecifiers.createFromRenderedImage(image.getRenderedImage());
IIOMetadata nativeMetadata = delegate.getDefaultImageMetadata(type, param); IIOMetadata nativeMetadata = delegate.getDefaultImageMetadata(type, param);
JPEGImage10Metadata metadata = (JPEGImage10Metadata) image.getMetadata(); JPEGImage10Metadata metadata = (JPEGImage10Metadata) image.getMetadata();
@@ -184,23 +186,67 @@ public final class JPEGImageWriter extends ImageWriterBase {
RenderedImage renderedImage = image.getRenderedImage(); RenderedImage renderedImage = image.getRenderedImage();
boolean overrideDestination = param != null && param.getDestinationType() != null; boolean overrideDestination = param != null && param.getDestinationType() != null;
ImageTypeSpecifier destinationType = overrideDestination ImageTypeSpecifier destinationType = overrideDestination
? param.getDestinationType() ? param.getDestinationType()
: ImageTypeSpecifier.createFromRenderedImage(renderedImage); : ImageTypeSpecifiers.createFromRenderedImage(renderedImage);
ColorSpace cmykCS = destinationType.getColorModel().getColorSpace(); IIOMetadata metadata = convertCMYKMetadata(image.getMetadata(), destinationType, param);
IIOMetadata metadata = delegate.getDefaultImageMetadata(destinationType, param); Raster raster = new InvertedRaster(getRaster(renderedImage));
// TODO: For YCCK we need oposite conversion
// for (int i = 0; i < data.length; i += 4) {
// YCbCrConverter.convertYCbCr2RGB(data, data, i);
// }
if (overrideDestination) {
// Avoid javax.imageio.IIOException: Invalid argument to native writeImage
param.setDestinationType(null);
}
try {
delegate.write(streamMetadata, new IIOImage(raster, null, metadata), param);
}
finally {
if (overrideDestination) {
param.setDestinationType(destinationType);
}
}
}
private IIOMetadata convertCMYKMetadata(IIOMetadata original, ImageTypeSpecifier destinationType, ImageWriteParam param) throws IIOInvalidTreeException {
IIOMetadataNode jpegMeta = new IIOMetadataNode(JAVAX_IMAGEIO_JPEG_IMAGE_1_0); IIOMetadataNode jpegMeta = new IIOMetadataNode(JAVAX_IMAGEIO_JPEG_IMAGE_1_0);
jpegMeta.appendChild(new IIOMetadataNode("JPEGVariety")); // Just leave as default jpegMeta.appendChild(new IIOMetadataNode("JPEGVariety")); // Just leave as default, we can't write JFIF
IIOMetadataNode markerSequence = new IIOMetadataNode("markerSequence"); IIOMetadataNode markerSequence = new IIOMetadataNode("markerSequence");
jpegMeta.appendChild(markerSequence); jpegMeta.appendChild(markerSequence);
IIOMetadataNode originalTree = original != null
? (IIOMetadataNode) original.getAsTree(JAVAX_IMAGEIO_JPEG_IMAGE_1_0)
: new IIOMetadataNode("emptyNode");
// Append original unknown nodes, if present, but filter out any ICC Profiles
NodeList unknowns = originalTree.getElementsByTagName("unknown");
for (int i = 0; i < unknowns.getLength(); i++) {
IIOMetadataNode unknown = (IIOMetadataNode) unknowns.item(i);
// TODO: If the cmykCS is not an ICC profile, maybe it makes sense to NOT filter here? that's a corner case...
if ("226".equals(unknown.getAttribute("MarkerTag"))) {
Object userObject = unknown.getUserObject();
if (userObject instanceof byte[] && ((byte[]) userObject).length >= "ICC_PROFILE".length()
&& "ICC_PROFILE".equals(new String((byte[]) userObject, 0, "ICC_PROFILE".length()))) {
continue;
}
}
markerSequence.appendChild(unknown);
}
IIOMetadataNode app14Adobe = new IIOMetadataNode("app14Adobe"); IIOMetadataNode app14Adobe = new IIOMetadataNode("app14Adobe");
app14Adobe.setAttribute("transform", "0"); // 0 for CMYK, 2 for YCCK app14Adobe.setAttribute("transform", "0"); // 0 for CMYK, 2 for YCCK
markerSequence.appendChild(app14Adobe); markerSequence.appendChild(app14Adobe);
ColorSpace cmykCS = destinationType.getColorModel().getColorSpace();
if (cmykCS instanceof ICC_ColorSpace) { if (cmykCS instanceof ICC_ColorSpace) {
ICC_Profile profile = ((ICC_ColorSpace) cmykCS).getProfile(); ICC_Profile profile = ((ICC_ColorSpace) cmykCS).getProfile();
byte[] profileData = profile.getData(); byte[] profileData = profile.getData();
@@ -233,28 +279,16 @@ public final class JPEGImageWriter extends ImageWriterBase {
} }
} }
// Append original comment nodes, if present
NodeList comments = originalTree.getElementsByTagName("COM");
for (int i = 0; i < comments.getLength(); i++) {
markerSequence.appendChild(comments.item(i));
}
IIOMetadata metadata = delegate.getDefaultImageMetadata(destinationType, param);
metadata.mergeTree(JAVAX_IMAGEIO_JPEG_IMAGE_1_0, jpegMeta); metadata.mergeTree(JAVAX_IMAGEIO_JPEG_IMAGE_1_0, jpegMeta);
Raster raster = new InvertedRaster(getRaster(renderedImage)); return metadata;
// TODO: For YCCK we need oposite conversion
// for (int i = 0; i < data.length; i += 4) {
// YCbCrConverter.convertYCbCr2RGB(data, data, i);
// }
if (overrideDestination) {
// Avoid javax.imageio.IIOException: Invalid argument to native writeImage
param.setDestinationType(null);
}
try {
delegate.write(streamMetadata, new IIOImage(raster, null, metadata), param);
}
finally {
if (overrideDestination) {
param.setDestinationType(destinationType);
}
}
} }
// TODO: Candidate util method // TODO: Candidate util method
@@ -38,7 +38,13 @@ import com.twelvemonkeys.imageio.util.ImageWriterAbstractTest;
import org.junit.Test; import org.junit.Test;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import javax.imageio.*; import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOMetadata; import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataFormatImpl; import javax.imageio.metadata.IIOMetadataFormatImpl;
import javax.imageio.metadata.IIOMetadataNode; import javax.imageio.metadata.IIOMetadataNode;
@@ -48,8 +54,7 @@ import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream; import javax.imageio.stream.ImageOutputStream;
import javax.imageio.stream.MemoryCacheImageOutputStream; import javax.imageio.stream.MemoryCacheImageOutputStream;
import java.awt.*; import java.awt.*;
import java.awt.color.ColorSpace; import java.awt.color.*;
import java.awt.color.ICC_Profile;
import java.awt.image.*; import java.awt.image.*;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
@@ -211,7 +216,7 @@ public class JPEGImageWriterTest extends ImageWriterAbstractTest<JPEGImageWriter
// Test APP2/ICC_PROFILE segments form native metadata // Test APP2/ICC_PROFILE segments form native metadata
IIOMetadataNode nativeMeta = (IIOMetadataNode) metadata.getAsTree(JPEGImage10Metadata.JAVAX_IMAGEIO_JPEG_IMAGE_1_0); IIOMetadataNode nativeMeta = (IIOMetadataNode) metadata.getAsTree(JPEGImage10Metadata.JAVAX_IMAGEIO_JPEG_IMAGE_1_0);
NodeList unknown = nativeMeta.getElementsByTagName("unknown"); NodeList unknown = nativeMeta.getElementsByTagName("unknown");
assertEquals(11, unknown.getLength()); // We write longer segments than the original, so we get less segments assertEquals(14, unknown.getLength()); // We write longer segments than the original, so we get less segments
ByteArrayOutputStream iccSegments = new ByteArrayOutputStream(1024 * 1024); ByteArrayOutputStream iccSegments = new ByteArrayOutputStream(1024 * 1024);
@@ -238,7 +243,6 @@ public class JPEGImageWriterTest extends ImageWriterAbstractTest<JPEGImageWriter
ImageWriter writer = createWriter(); ImageWriter writer = createWriter();
ImageReader reader = ImageIO.getImageReader(writer); ImageReader reader = ImageIO.getImageReader(writer);
// TODO: Add flag to allow removing the ICC profile from image
ByteArrayOutputStream stream = transcode(reader, getClassLoaderResource("/jpeg/cmyk-sample-multiple-chunk-icc.jpg"), writer, ColorSpace.TYPE_CMYK, false); ByteArrayOutputStream stream = transcode(reader, getClassLoaderResource("/jpeg/cmyk-sample-multiple-chunk-icc.jpg"), writer, ColorSpace.TYPE_CMYK, false);
reader.reset(); reader.reset();
@@ -259,7 +263,7 @@ public class JPEGImageWriterTest extends ImageWriterAbstractTest<JPEGImageWriter
// Test APP2/ICC_PROFILE segments form native metadata // Test APP2/ICC_PROFILE segments form native metadata
IIOMetadataNode nativeMeta = (IIOMetadataNode) metadata.getAsTree(JPEGImage10Metadata.JAVAX_IMAGEIO_JPEG_IMAGE_1_0); IIOMetadataNode nativeMeta = (IIOMetadataNode) metadata.getAsTree(JPEGImage10Metadata.JAVAX_IMAGEIO_JPEG_IMAGE_1_0);
NodeList unknown = nativeMeta.getElementsByTagName("unknown"); NodeList unknown = nativeMeta.getElementsByTagName("unknown");
assertEquals(0, unknown.getLength()); assertEquals(3, unknown.getLength());
} }
// TODO: YCCK // TODO: YCCK
+11 -2
View File
@@ -3,13 +3,13 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.9.0</version> <version>3.10.2-SNAPSHOT</version>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<artifactId>imageio-metadata</artifactId> <artifactId>imageio-metadata</artifactId>
<name>TwelveMonkeys :: ImageIO :: Metadata</name> <name>TwelveMonkeys :: ImageIO :: Metadata</name>
<description> <description>
ImageIO metadata module. TwelveMonkeys ImageIO metadata support classes.
</description> </description>
<properties> <properties>
@@ -28,4 +28,13 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
</plugin>
</plugins>
</build>
</project> </project>
@@ -35,8 +35,11 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
@@ -50,6 +53,7 @@ import java.util.Iterator;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.ImageInputStream;
import com.twelvemonkeys.imageio.stream.DirectImageInputStream;
import org.junit.Test; import org.junit.Test;
import com.twelvemonkeys.imageio.metadata.CompoundDirectory; import com.twelvemonkeys.imageio.metadata.CompoundDirectory;
@@ -490,12 +494,15 @@ public class XMPReaderTest extends MetadataReaderAbstractTest {
assertThat(exif.getEntryById("http://ns.adobe.com/exif/1.0/NativeDigest"), hasValue("36864,40960,40961,37121,37122,40962,40963,37510,40964,36867,36868,33434,33437,34850,34852,34855,34856,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386,37396,41483,41484,41486,41487,41488,41492,41493,41495,41728,41729,41730,41985,41986,41987,41988,41989,41990,41991,41992,41993,41994,41995,41996,42016,0,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,23,24,25,26,27,28,30;A7F21D25E2C562F152B2C4ECC9E534DA")); assertThat(exif.getEntryById("http://ns.adobe.com/exif/1.0/NativeDigest"), hasValue("36864,40960,40961,37121,37122,40962,40963,37510,40964,36867,36868,33434,33437,34850,34852,34855,34856,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386,37396,41483,41484,41486,41487,41488,41492,41493,41495,41728,41729,41730,41985,41986,41987,41988,41989,41990,41991,41992,41993,41994,41995,41996,42016,0,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,23,24,25,26,27,28,30;A7F21D25E2C562F152B2C4ECC9E534DA"));
} }
@Test(timeout = 1500L) @Test(timeout = 2500L)
public void testNoExternalRequest() throws Exception { public void testNoExternalRequest() throws Exception {
// TODO: Use dynamic port? String maliciousXML = resourceAsString("/xmp/xmp-jpeg-xxe.xml");
try (HTTPServer server = new HTTPServer(7777)) {
try { try (HTTPServer server = new HTTPServer()) {
createReader().read(getResourceAsIIS("/xmp/xmp-jpeg-xxe.xml")); String dynamicXML = maliciousXML.replace("http://localhost:7777/", "http://localhost:" + server.port() + "/");
try (DirectImageInputStream input = new DirectImageInputStream(new ByteArrayInputStream(dynamicXML.getBytes(StandardCharsets.UTF_8)));) {
createReader().read(input);
} catch (IOException ioe) { } catch (IOException ioe) {
if (ioe.getMessage().contains("501")) { if (ioe.getMessage().contains("501")) {
throw new AssertionError("Reading should not cause external requests", ioe); throw new AssertionError("Reading should not cause external requests", ioe);
@@ -507,12 +514,26 @@ public class XMPReaderTest extends MetadataReaderAbstractTest {
} }
} }
private String resourceAsString(String name) throws IOException {
StringBuilder builder = new StringBuilder(1024);
try (BufferedReader reader = new BufferedReader(new InputStreamReader(getResource(name).openStream(), StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
builder.append(line)
.append('\n');
}
}
return builder.toString();
}
private static class HTTPServer implements AutoCloseable { private static class HTTPServer implements AutoCloseable {
private final ServerSocket server; private final ServerSocket server;
private final Thread thread; private final Thread thread;
HTTPServer(int port) throws IOException { HTTPServer() throws IOException {
server = new ServerSocket(port, 1); server = new ServerSocket(0, 1);
thread = new Thread(new Runnable() { thread = new Thread(new Runnable() {
@Override public void run() { @Override public void run() {
serve(); serve();
@@ -521,6 +542,10 @@ public class XMPReaderTest extends MetadataReaderAbstractTest {
thread.start(); thread.start();
} }
public final int port() {
return server.getLocalPort();
}
private void serve() { private void serve() {
try { try {
Socket client = server.accept(); Socket client = server.accept();
+18 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.9.0</version> <version>3.10.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-pcx</artifactId> <artifactId>imageio-pcx</artifactId>
<name>TwelveMonkeys :: ImageIO :: PCX plugin</name> <name>TwelveMonkeys :: ImageIO :: PCX plugin</name>
@@ -28,4 +28,21 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </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> </project>
@@ -13,7 +13,6 @@ final class PCXMetadata extends StandardImageMetadataSupport {
} }
private static PlanarConfiguration planarConfiguration(PCXHeader header) { private static PlanarConfiguration planarConfiguration(PCXHeader header) {
System.out.println("header = " + header);
return header.getChannels() > 1 ? PlanarConfiguration.LineInterleaved : null; return header.getChannels() > 1 ? PlanarConfiguration.LineInterleaved : null;
} }
@@ -25,6 +24,6 @@ final class PCXMetadata extends StandardImageMetadataSupport {
return "RLE"; return "RLE";
} }
return "Uknown"; return "Unknown";
} }
} }
+10 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.9.0</version> <version>3.10.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-pdf</artifactId> <artifactId>imageio-pdf</artifactId>
<name>TwelveMonkeys :: ImageIO :: PDF plugin</name> <name>TwelveMonkeys :: ImageIO :: PDF plugin</name>
@@ -28,4 +28,13 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
</plugin>
</plugins>
</build>
</project> </project>
+19 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.9.0</version> <version>3.10.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-pict</artifactId> <artifactId>imageio-pict</artifactId>
<name>TwelveMonkeys :: ImageIO :: PICT plugin</name> <name>TwelveMonkeys :: ImageIO :: PICT plugin</name>
@@ -27,4 +27,22 @@
</dependency> </dependency>
</dependencies> </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> </project>
+20 -1
View File
@@ -4,7 +4,7 @@
<parent> <parent>
<groupId>com.twelvemonkeys.imageio</groupId> <groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId> <artifactId>imageio</artifactId>
<version>3.9.0</version> <version>3.10.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>imageio-pnm</artifactId> <artifactId>imageio-pnm</artifactId>
<name>TwelveMonkeys :: ImageIO :: PNM plugin</name> <name>TwelveMonkeys :: ImageIO :: PNM plugin</name>
@@ -28,4 +28,23 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </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> </project>
@@ -30,8 +30,6 @@
package com.twelvemonkeys.imageio.plugins.pnm; package com.twelvemonkeys.imageio.plugins.pnm;
import com.twelvemonkeys.imageio.ImageWriterBase;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
import javax.imageio.IIOImage; import javax.imageio.IIOImage;
@@ -40,7 +38,7 @@ import javax.imageio.metadata.IIOMetadataFormatImpl;
import javax.imageio.metadata.IIOMetadataNode; import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.spi.ImageWriterSpi; import javax.imageio.spi.ImageWriterSpi;
import javax.imageio.stream.ImageOutputStream; import javax.imageio.stream.ImageOutputStream;
import java.awt.image.DataBuffer; import java.awt.image.*;
import java.io.IOException; import java.io.IOException;
import java.util.Locale; import java.util.Locale;
@@ -53,11 +51,7 @@ abstract class HeaderWriter {
this.imageOutput = imageOutput; this.imageOutput = imageOutput;
} }
public static void write(final IIOImage image, final ImageWriterBase writer, final ImageOutputStream imageOutput) throws IOException { static HeaderWriter createHeaderWriter(final String formatName, final ImageOutputStream imageOutput) {
createHeaderWriter(writer.getFormatName(), imageOutput).writeHeader(image, writer.getOriginatingProvider());
}
private static HeaderWriter createHeaderWriter(final String formatName, final ImageOutputStream imageOutput) {
if (formatName.equals("pam")) { if (formatName.equals("pam")) {
return new PAMHeaderWriter(imageOutput); return new PAMHeaderWriter(imageOutput);
} }
@@ -83,25 +77,36 @@ abstract class HeaderWriter {
return image.hasRaster() ? image.getRaster().getNumBands() : image.getRenderedImage().getSampleModel().getNumBands(); return image.hasRaster() ? image.getRaster().getNumBands() : image.getRenderedImage().getSampleModel().getNumBands();
} }
protected final SampleModel getSampleModel(final IIOImage image) {
return image.hasRaster() ? image.getRaster().getSampleModel() : image.getRenderedImage().getSampleModel();
}
protected int getMaxVal(final IIOImage image) { protected int getMaxVal(final IIOImage image) {
int transferType = getTransferType(image); int transferType = getTransferType(image);
if (transferType == DataBuffer.TYPE_BYTE) { switch (transferType) {
return PNM.MAX_VAL_8BIT; case DataBuffer.TYPE_BYTE:
} return PNM.MAX_VAL_8BIT;
else if (transferType == DataBuffer.TYPE_USHORT) {
return PNM.MAX_VAL_16BIT; case DataBuffer.TYPE_USHORT:
} return PNM.MAX_VAL_16BIT;
// else if (transferType == DataBuffer.TYPE_INT) {
// TODO: Support TYPE_INT through conversion, if number of channels is 3 or 4 (TYPE_INT_RGB, TYPE_INT_ARGB) case DataBuffer.TYPE_INT:
// } // We support TYPE_INT through conversion, if number of channels is 3 or 4 (TYPE_INT_RGB, TYPE_INT_ARGB)
else { SampleModel sampleModel = getSampleModel(image);
throw new IllegalArgumentException("Unsupported data type: " + transferType); int numBands = sampleModel.getNumBands();
if (sampleModel instanceof SinglePixelPackedSampleModel && (numBands == 3 || numBands == 4)) {
return PNM.MAX_VAL_8BIT;
}
// ...else fall through
default:
throw new IllegalArgumentException("Unsupported data type: " + transferType);
} }
} }
protected final int getTransferType(final IIOImage image) { protected final int getTransferType(final IIOImage image) {
return image.hasRaster() ? image.getRaster().getTransferType() : image.getRenderedImage().getSampleModel().getTransferType(); return image.hasRaster() ? image.getRaster().getTransferType() : image.getRenderedImage().getSampleModel().getTransferType();
} }
protected final void writeComments(final IIOMetadata metadata, final ImageWriterSpi provider) throws IOException { protected final void writeComments(final IIOMetadata metadata, final ImageWriterSpi provider) throws IOException {
@@ -120,5 +125,4 @@ abstract class HeaderWriter {
} }
} }
} }
} }
@@ -30,6 +30,8 @@
package com.twelvemonkeys.imageio.plugins.pnm; package com.twelvemonkeys.imageio.plugins.pnm;
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
import javax.imageio.IIOImage; import javax.imageio.IIOImage;
import javax.imageio.spi.ImageWriterSpi; import javax.imageio.spi.ImageWriterSpi;
import javax.imageio.stream.ImageOutputStream; import javax.imageio.stream.ImageOutputStream;
@@ -44,6 +46,8 @@ final class PAMHeaderWriter extends HeaderWriter {
@Override @Override
public void writeHeader(final IIOImage image, final ImageWriterSpi provider) throws IOException { public void writeHeader(final IIOImage image, final ImageWriterSpi provider) throws IOException {
TupleType tupleType = tupleType(image);
// Write PAM magic // Write PAM magic
imageOutput.writeShort(PNM.PAM); imageOutput.writeShort(PNM.PAM);
imageOutput.write('\n'); imageOutput.write('\n');
@@ -52,12 +56,19 @@ final class PAMHeaderWriter extends HeaderWriter {
// Write width/height and number of channels // Write width/height and number of channels
imageOutput.write(String.format("WIDTH %s\nHEIGHT %s\n", getWidth(image), getHeight(image)).getBytes(UTF_8)); imageOutput.write(String.format("WIDTH %s\nHEIGHT %s\n", getWidth(image), getHeight(image)).getBytes(UTF_8));
imageOutput.write(String.format("DEPTH %s\n", getNumBands(image)).getBytes(UTF_8)); imageOutput.write(String.format("DEPTH %s\n", getNumBands(image)).getBytes(UTF_8));
// TODO: maxSample (8 or16 bit)
imageOutput.write(String.format("MAXVAL %s\n", getMaxVal(image)).getBytes(UTF_8)); imageOutput.write(String.format("MAXVAL %s\n", getMaxVal(image)).getBytes(UTF_8));
// TODO: Determine tuple type based on input color model and image data
TupleType tupleType = getNumBands(image) > 3 ? TupleType.RGB_ALPHA : TupleType.RGB;
imageOutput.write(String.format("TUPLTYPE %s\nENDHDR\n", tupleType).getBytes(UTF_8)); imageOutput.write(String.format("TUPLTYPE %s\nENDHDR\n", tupleType).getBytes(UTF_8));
} }
private static TupleType tupleType(IIOImage image) {
TupleType tupleType = image.hasRaster()
? TupleType.forPAM(image.getRaster())
: TupleType.forPAM(ImageTypeSpecifiers.createFromRenderedImage(image.getRenderedImage()));
if (tupleType == null) {
throw new IllegalArgumentException("Unknown TupleType for " + (image.hasRaster() ? image.getRaster() : image.getRenderedImage()));
}
return tupleType;
}
} }
@@ -45,12 +45,11 @@ public final class PAMImageWriterSpi extends ImageWriterSpiBase {
super(new PAMProviderInfo()); super(new PAMProviderInfo());
} }
public boolean canEncodeImage(final ImageTypeSpecifier pType) { public boolean canEncodeImage(final ImageTypeSpecifier type) {
// TODO: FixMe return TupleType.forPAM(type) != null;
return true;
} }
public ImageWriter createWriterInstance(final Object pExtension) { public ImageWriter createWriterInstance(final Object extension) {
return new PNMImageWriter(this); return new PNMImageWriter(this);
} }
@@ -69,7 +69,7 @@ final class PFMHeaderParser extends HeaderParser {
public PNMHeader parse() throws IOException { public PNMHeader parse() throws IOException {
int width = 0; int width = 0;
int height = 0; int height = 0;
float maxSample = tupleType == TupleType.BLACKANDWHITE_WHITE_IS_ZERO ? 1 : 0; // PBM has no maxSample line float maxSample = 0;
List<String> comments = new ArrayList<>(); List<String> comments = new ArrayList<>();
@@ -77,7 +77,7 @@ final class PFMHeaderParser extends HeaderParser {
String line = input.readLine(); String line = input.readLine();
if (line == null) { if (line == null) {
throw new IIOException("Unexpeced end of stream"); throw new IIOException("Unexpected end of stream");
} }
int commentStart = line.indexOf('#'); int commentStart = line.indexOf('#');
@@ -30,6 +30,8 @@
package com.twelvemonkeys.imageio.plugins.pnm; package com.twelvemonkeys.imageio.plugins.pnm;
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
import javax.imageio.IIOImage; import javax.imageio.IIOImage;
import javax.imageio.spi.ImageWriterSpi; import javax.imageio.spi.ImageWriterSpi;
import javax.imageio.stream.ImageOutputStream; import javax.imageio.stream.ImageOutputStream;
@@ -45,8 +47,7 @@ final class PNMHeaderWriter extends HeaderWriter {
@Override @Override
public void writeHeader(final IIOImage image, final ImageWriterSpi provider) throws IOException { public void writeHeader(final IIOImage image, final ImageWriterSpi provider) throws IOException {
// Write P4/P5/P6 magic (Support only RAW formats for now; if we are to support PLAIN formats, pass parameter) // Write P4/P5/P6 magic (Support only RAW formats for now; if we are to support PLAIN formats, pass parameter)
// TODO: Determine PBM, PBM or PPM based on input color model and image data? short type = type(image);
short type = PNM.PPM;
imageOutput.writeShort(type); imageOutput.writeShort(type);
imageOutput.write('\n'); imageOutput.write('\n');
@@ -61,4 +62,35 @@ final class PNMHeaderWriter extends HeaderWriter {
imageOutput.write(String.format("%s\n", getMaxVal(image)).getBytes(UTF_8)); imageOutput.write(String.format("%s\n", getMaxVal(image)).getBytes(UTF_8));
} }
} }
private short type(IIOImage image) {
TupleType type = tupleType(image);
if (type != null) {
switch (type) {
case BLACKANDWHITE_WHITE_IS_ZERO:
return PNM.PBM;
case GRAYSCALE:
return PNM.PGM;
case RGB:
return PNM.PPM;
default:
// fall through...
}
}
throw new IllegalArgumentException("Unsupported tupleType: " + type);
}
private static TupleType tupleType(IIOImage image) {
TupleType tupleType = image.hasRaster()
? TupleType.forPNM(image.getRaster())
: TupleType.forPNM(ImageTypeSpecifiers.createFromRenderedImage(image.getRenderedImage()));
if (tupleType == null) {
throw new IllegalArgumentException("Unknown TupleType for " + (image.hasRaster() ? image.getRaster() : image.getRenderedImage()));
}
return tupleType;
}
} }
@@ -31,14 +31,17 @@
package com.twelvemonkeys.imageio.plugins.pnm; package com.twelvemonkeys.imageio.plugins.pnm;
import com.twelvemonkeys.imageio.ImageWriterBase; import com.twelvemonkeys.imageio.ImageWriterBase;
import com.twelvemonkeys.imageio.util.RasterUtils;
import javax.imageio.*; import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.metadata.IIOMetadata; import javax.imageio.metadata.IIOMetadata;
import javax.imageio.spi.ImageWriterSpi; import javax.imageio.spi.ImageWriterSpi;
import java.awt.image.BufferedImage; import javax.imageio.stream.ImageOutputStream;
import java.awt.image.DataBuffer; import java.awt.image.*;
import java.awt.image.Raster;
import java.awt.image.SampleModel;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@@ -69,7 +72,7 @@ public final class PNMImageWriter extends ImageWriterBase {
// TODO: Issue warning if streamMetadata is non-null? // TODO: Issue warning if streamMetadata is non-null?
// TODO: Issue warning if IIOImage contains thumbnails or other data we can't store? // TODO: Issue warning if IIOImage contains thumbnails or other data we can't store?
HeaderWriter.write(image, this, imageOutput); writeHeader(image, this, imageOutput);
// TODO: Sub region // TODO: Sub region
// TODO: Subsampling // TODO: Subsampling
@@ -80,16 +83,20 @@ public final class PNMImageWriter extends ImageWriterBase {
processImageComplete(); processImageComplete();
} }
private void writeHeader(final IIOImage image, final ImageWriterBase writer, final ImageOutputStream imageOutput) throws IOException {
HeaderWriter.createHeaderWriter(writer.getFormatName(), imageOutput).writeHeader(image, writer.getOriginatingProvider());
}
private void writeImageData(final IIOImage image) throws IOException { private void writeImageData(final IIOImage image) throws IOException {
// - dump data as is (or convert, if TYPE_INT_xxx) // - dump data as is (or convert, if TYPE_INT_xxx
// Enforce RGB/CMYK order for such data! // Enforce RGB/CMYK order for such data!
// TODO: Loop over x/y tiles, using 0,0 is only valid for BufferedImage // TODO: Loop over x/y tiles, using 0,0 is only valid for BufferedImage
// TODO: PNM/PAM does not support tiling, we must iterate all tiles along the x-axis for each row we write // TODO: PNM/PAM does not support tiling, we must iterate all tiles along the x-axis for each row we write
Raster tile = image.hasRaster() ? image.getRaster() : image.getRenderedImage().getTile(0, 0); Raster tile = image.hasRaster() ? image.getRaster() : image.getRenderedImage().getTile(0, 0);
tile = tile.getTransferType() == DataBuffer.TYPE_INT ? RasterUtils.asByteRaster(tile) : tile;
SampleModel sampleModel = tile.getSampleModel(); SampleModel sampleModel = tile.getSampleModel();
DataBuffer dataBuffer = tile.getDataBuffer(); DataBuffer dataBuffer = tile.getDataBuffer();
int tileWidth = tile.getWidth(); int tileWidth = tile.getWidth();
@@ -48,12 +48,11 @@ public final class PNMImageWriterSpi extends ImageWriterSpiBase {
super(new PNMProviderInfo()); super(new PNMProviderInfo());
} }
public boolean canEncodeImage(final ImageTypeSpecifier pType) { public boolean canEncodeImage(final ImageTypeSpecifier type) {
// TODO: FixMe: Support only 1 bit b/w, 8-16 bit gray and 8-16 bit/sample RGB return TupleType.forPNM(type) != null;
return true;
} }
public ImageWriter createWriterInstance(final Object pExtension) { public ImageWriter createWriterInstance(final Object extension) {
return new PNMImageWriter(this); return new PNMImageWriter(this);
} }
@@ -30,7 +30,10 @@
package com.twelvemonkeys.imageio.plugins.pnm; package com.twelvemonkeys.imageio.plugins.pnm;
import javax.imageio.ImageTypeSpecifier;
import java.awt.*; import java.awt.*;
import java.awt.color.*;
import java.awt.image.*;
enum TupleType { enum TupleType {
// Official: // Official:
@@ -80,4 +83,150 @@ enum TupleType {
public boolean isValidMaxSample(int maxSample) { public boolean isValidMaxSample(int maxSample) {
return maxSample >= minMaxSample && maxSample <= maxMaxSample; return maxSample >= minMaxSample && maxSample <= maxMaxSample;
} }
static TupleType forPNM(Raster raster) {
return filterPNM(forPAM(raster));
}
static TupleType forPNM(ImageTypeSpecifier type) {
return filterPNM(forPAM(type));
}
private static TupleType filterPNM(TupleType tupleType) {
if (tupleType == null) {
return null;
}
switch (tupleType) {
case BLACKANDWHITE:
return BLACKANDWHITE_WHITE_IS_ZERO;
case GRAYSCALE:
case RGB:
return tupleType;
default:
return null;
}
}
static TupleType forPAM(Raster raster) {
SampleModel sampleModel = raster.getSampleModel();
switch (sampleModel.getTransferType()) {
case DataBuffer.TYPE_BYTE:
case DataBuffer.TYPE_USHORT:
case DataBuffer.TYPE_INT:
// B/W, Gray or RGB
int bands = sampleModel.getNumBands();
if (bands == 1 && sampleModel.getSampleSize(0) == 1) {
return TupleType.BLACKANDWHITE;
}
else if (bands == 2 && sampleModel.getSampleSize(0) == 1 && sampleModel.getSampleSize(1) == 1) {
return TupleType.BLACKANDWHITE_ALPHA;
}
// We can only write 8 or 16 bits/band
if (!(sampleModel.getSampleSize(0) == 8 || sampleModel.getSampleSize(0) == 16)) {
return null;
}
for (int i = 1; i < bands; i++) {
if (sampleModel.getSampleSize(0) != sampleModel.getSampleSize(i)) {
return null;
}
}
if (bands == 1) {
return TupleType.GRAYSCALE;
}
else if (bands == 2) {
return TupleType.GRAYSCALE_ALPHA;
}
else if (bands == 3) {
return TupleType.RGB;
}
else if (bands == 4) {
return TupleType.RGB_ALPHA;
}
// ...else fall through...
}
return null;
}
static TupleType forPAM(ImageTypeSpecifier type) {
// Support only 1 bit b/w, 8-16 bit gray and 8-16 bit/sample RGB
switch (type.getBufferedImageType()) {
// 1 bit b/w or b/w + a
case BufferedImage.TYPE_BYTE_BINARY:
switch (type.getNumBands()) {
case 1:
return type.getBitsPerBand(0) == 1 ? TupleType.BLACKANDWHITE : null;
case 2:
return type.getBitsPerBand(0) == 2 || type.getBitsPerBand(0) == 1 && type.getBitsPerBand(1) == 1 ? TupleType.BLACKANDWHITE_ALPHA : null;
default:
return null;
}
// Gray
case BufferedImage.TYPE_BYTE_GRAY:
case BufferedImage.TYPE_USHORT_GRAY:
return TupleType.GRAYSCALE;
// RGB
case BufferedImage.TYPE_3BYTE_BGR:
case BufferedImage.TYPE_INT_RGB:
case BufferedImage.TYPE_INT_BGR:
return TupleType.RGB;
// RGBA
case BufferedImage.TYPE_4BYTE_ABGR:
case BufferedImage.TYPE_4BYTE_ABGR_PRE:
case BufferedImage.TYPE_INT_ARGB:
case BufferedImage.TYPE_INT_ARGB_PRE:
return TupleType.RGB_ALPHA;
default:
// BYTE, USHORT or INT (packed)
switch (type.getSampleModel().getTransferType()) {
case DataBuffer.TYPE_BYTE:
case DataBuffer.TYPE_USHORT:
case DataBuffer.TYPE_INT:
// Gray or RGB
ColorModel colorModel = type.getColorModel();
if (!(colorModel instanceof IndexColorModel)) {
ColorSpace cs = colorModel.getColorSpace();
// We can only write 8 or 16 bits/band
int bands = type.getNumBands();
if (!(type.getBitsPerBand(0) == 8 || type.getBitsPerBand(0) == 16)) {
return null;
}
for (int i = 1; i < bands; i++) {
if (type.getBitsPerBand(0) != type.getBitsPerBand(i)) {
return null;
}
}
if (cs.getType() == ColorSpace.TYPE_GRAY && bands == 1) {
return TupleType.GRAYSCALE;
}
else if (cs.getType() == ColorSpace.TYPE_GRAY && colorModel.hasAlpha() && bands == 2) {
return TupleType.GRAYSCALE_ALPHA;
}
else if (cs.getType() == ColorSpace.TYPE_RGB && bands == 3) {
return TupleType.RGB;
}
else if (cs.getType() == ColorSpace.TYPE_RGB && colorModel.hasAlpha() && bands == 4) {
return TupleType.RGB_ALPHA;
}
else if (cs.getType() == ColorSpace.TYPE_CMYK && bands == 4) {
return TupleType.CMYK;
}
else if (cs.getType() == ColorSpace.TYPE_CMYK && colorModel.hasAlpha() && bands == 5) {
return TupleType.CMYK_ALPHA;
}
// ...else fall through...
}
}
}
return null;
}
} }
@@ -30,15 +30,23 @@
package com.twelvemonkeys.imageio.plugins.pnm; package com.twelvemonkeys.imageio.plugins.pnm;
import com.twelvemonkeys.imageio.color.ColorSpaces;
import org.junit.Test; import org.junit.Test;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriter; import javax.imageio.ImageWriter;
import javax.imageio.spi.ImageReaderSpi; import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.spi.ImageWriterSpi; import javax.imageio.spi.ImageWriterSpi;
import java.awt.*;
import java.awt.color.*;
import java.awt.image.*;
import static com.twelvemonkeys.imageio.spi.ReaderWriterProviderInfoTest.assertClassExists; import static com.twelvemonkeys.imageio.spi.ReaderWriterProviderInfoTest.assertClassExists;
import static com.twelvemonkeys.imageio.spi.ReaderWriterProviderInfoTest.assertClassesExist; import static com.twelvemonkeys.imageio.spi.ReaderWriterProviderInfoTest.assertClassesExist;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
/** /**
* PAMImageWriterSpiTest. * PAMImageWriterSpiTest.
@@ -65,4 +73,85 @@ public class PAMImageWriterSpiTest {
public void getOutputTypes() { public void getOutputTypes() {
assertNotNull(spi.getOutputTypes()); assertNotNull(spi.getOutputTypes());
} }
@Test
public void canEncodeImageBinary() {
assertTrue(spi.canEncodeImage(new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_BINARY)));
assertTrue(spi.canEncodeImage(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_BYTE_BINARY)));
}
@Test
public void canNotEncodeImageIndexed() {
assertFalse(spi.canEncodeImage(new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_INDEXED)));
assertFalse(spi.canEncodeImage(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_BYTE_INDEXED)));
}
@Test
public void canEncodeImageGray() {
assertTrue(spi.canEncodeImage(new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_GRAY)));
assertTrue(spi.canEncodeImage(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY)));
assertTrue(spi.canEncodeImage(new BufferedImage(1, 1, BufferedImage.TYPE_USHORT_GRAY)));
assertTrue(spi.canEncodeImage(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_USHORT_GRAY)));
}
@Test
public void canEncodeImageGrayAlpha() {
ComponentColorModel grayAlphaByte = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
assertTrue(spi.canEncodeImage(new ImageTypeSpecifier(grayAlphaByte, grayAlphaByte.createCompatibleSampleModel(1, 1))));
ComponentColorModel grayAlphaUShort = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_USHORT);
assertTrue(spi.canEncodeImage(new ImageTypeSpecifier(grayAlphaUShort, grayAlphaUShort.createCompatibleSampleModel(1, 1))));
}
@Test
public void canEncodeImageRGB() {
assertTrue(spi.canEncodeImage(new BufferedImage(1, 1, BufferedImage.TYPE_3BYTE_BGR)));
assertTrue(spi.canEncodeImage(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR)));
assertTrue(spi.canEncodeImage(new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB)));
assertTrue(spi.canEncodeImage(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB)));
assertTrue(spi.canEncodeImage(new BufferedImage(1, 1, BufferedImage.TYPE_INT_BGR)));
assertTrue(spi.canEncodeImage(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_BGR)));
}
@Test
public void canEncodeImageARGB() {
assertTrue(spi.canEncodeImage(new BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR)));
assertTrue(spi.canEncodeImage(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR)));
assertTrue(spi.canEncodeImage(new BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR_PRE)));
assertTrue(spi.canEncodeImage(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR_PRE)));
assertTrue(spi.canEncodeImage(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)));
assertTrue(spi.canEncodeImage(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB)));
assertTrue(spi.canEncodeImage(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB_PRE)));
assertTrue(spi.canEncodeImage(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB_PRE)));
}
@Test
public void canEncodeImageCMYK() {
ComponentColorModel cmykByte = new ComponentColorModel(ColorSpaces.getColorSpace(ColorSpaces.CS_GENERIC_CMYK), false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
assertTrue(spi.canEncodeImage(new ImageTypeSpecifier(cmykByte, cmykByte.createCompatibleSampleModel(1, 1))));
ComponentColorModel cmykUShort = new ComponentColorModel(ColorSpaces.getColorSpace(ColorSpaces.CS_GENERIC_CMYK), false, false, Transparency.OPAQUE, DataBuffer.TYPE_USHORT);
assertTrue(spi.canEncodeImage(new ImageTypeSpecifier(cmykUShort, cmykUShort.createCompatibleSampleModel(1, 1))));
ComponentColorModel cmykAlphaByte = new ComponentColorModel(ColorSpaces.getColorSpace(ColorSpaces.CS_GENERIC_CMYK), true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
assertTrue(spi.canEncodeImage(new ImageTypeSpecifier(cmykAlphaByte, cmykAlphaByte.createCompatibleSampleModel(1, 1))));
ComponentColorModel cmykAlphaUShort = new ComponentColorModel(ColorSpaces.getColorSpace(ColorSpaces.CS_GENERIC_CMYK), true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_USHORT);
assertTrue(spi.canEncodeImage(new ImageTypeSpecifier(cmykAlphaUShort, cmykAlphaUShort.createCompatibleSampleModel(1, 1))));
}
@Test
public void canNotEncodeImageNonGrayOrRGB() {
ComponentColorModel xyzByte = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_CIEXYZ), false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
assertFalse(spi.canEncodeImage(new ImageTypeSpecifier(xyzByte, xyzByte.createCompatibleSampleModel(1, 1))));
ComponentColorModel xyzUshort = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_CIEXYZ), false, false, Transparency.OPAQUE, DataBuffer.TYPE_USHORT);
assertFalse(spi.canEncodeImage(new ImageTypeSpecifier(xyzUshort, xyzUshort.createCompatibleSampleModel(1, 1))));
}
} }
@@ -0,0 +1,37 @@
package com.twelvemonkeys.imageio.plugins.pnm;
import com.twelvemonkeys.imageio.color.ColorSpaces;
import com.twelvemonkeys.imageio.util.ImageWriterAbstractTest;
import javax.imageio.spi.ImageWriterSpi;
import java.awt.*;
import java.awt.color.*;
import java.awt.image.*;
import java.util.Arrays;
import java.util.List;
public class PAMImageWriterTest extends ImageWriterAbstractTest<PNMImageWriter> {
// NOTE: It's the same writer, however, the different SPI configures PAM mode, and enables extra formats
@Override
protected ImageWriterSpi createProvider() {
return new PAMImageWriterSpi();
}
@Override
protected List<? extends RenderedImage> getTestData() {
return Arrays.asList(
new BufferedImage(100, 100, BufferedImage.TYPE_BYTE_BINARY),
new BufferedImage(100, 100, BufferedImage.TYPE_3BYTE_BGR),
new BufferedImage(100, 100, BufferedImage.TYPE_BYTE_GRAY),
new BufferedImage(100, 100, BufferedImage.TYPE_USHORT_GRAY),
new BufferedImage(100, 100, BufferedImage.TYPE_4BYTE_ABGR),
new BufferedImage(100, 100, BufferedImage.TYPE_INT_BGR),
new BufferedImage(10, 10, BufferedImage.TYPE_INT_BGR),
new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB),
new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB_PRE),
new BufferedImage(new ComponentColorModel(ColorSpaces.getColorSpace(ColorSpace.CS_GRAY), true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_USHORT), Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT, 10, 10, 2, null), false, null),
new BufferedImage(new ComponentColorModel(ColorSpaces.getColorSpace(ColorSpaces.CS_GENERIC_CMYK), false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE), Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, 10, 10, 4, null), false, null),
new BufferedImage(new ComponentColorModel(ColorSpaces.getColorSpace(ColorSpaces.CS_GENERIC_CMYK), true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_USHORT), Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT, 10, 10, 5, null), false, null)
);
}
}
@@ -32,13 +32,19 @@ package com.twelvemonkeys.imageio.plugins.pnm;
import org.junit.Test; import org.junit.Test;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriter; import javax.imageio.ImageWriter;
import javax.imageio.spi.ImageReaderSpi; import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.spi.ImageWriterSpi; import javax.imageio.spi.ImageWriterSpi;
import java.awt.*;
import java.awt.color.*;
import java.awt.image.*;
import static com.twelvemonkeys.imageio.spi.ReaderWriterProviderInfoTest.assertClassExists; import static com.twelvemonkeys.imageio.spi.ReaderWriterProviderInfoTest.assertClassExists;
import static com.twelvemonkeys.imageio.spi.ReaderWriterProviderInfoTest.assertClassesExist; import static com.twelvemonkeys.imageio.spi.ReaderWriterProviderInfoTest.assertClassesExist;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
/** /**
* PNMImageWriterSpiTest. * PNMImageWriterSpiTest.
@@ -65,4 +71,70 @@ public class PNMImageWriterSpiTest {
public void getOutputTypes() { public void getOutputTypes() {
assertNotNull(spi.getOutputTypes()); assertNotNull(spi.getOutputTypes());
} }
@Test
public void canEncodeImageBinary() {
assertTrue(spi.canEncodeImage(new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_BINARY)));
assertTrue(spi.canEncodeImage(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_BYTE_BINARY)));
}
@Test
public void canNotEncodeImageIndexed() {
assertFalse(spi.canEncodeImage(new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_INDEXED)));
assertFalse(spi.canEncodeImage(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_BYTE_INDEXED)));
}
@Test
public void canEncodeImageGray() {
assertTrue(spi.canEncodeImage(new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_GRAY)));
assertTrue(spi.canEncodeImage(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY)));
assertTrue(spi.canEncodeImage(new BufferedImage(1, 1, BufferedImage.TYPE_USHORT_GRAY)));
assertTrue(spi.canEncodeImage(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_USHORT_GRAY)));
}
@Test
public void canNotEncodeImageGrayAlpha() {
ComponentColorModel grayAlphaByte = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
assertFalse(spi.canEncodeImage(new ImageTypeSpecifier(grayAlphaByte, grayAlphaByte.createCompatibleSampleModel(1, 1))));
ComponentColorModel grayAlphaUShort = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_USHORT);
assertFalse(spi.canEncodeImage(new ImageTypeSpecifier(grayAlphaUShort, grayAlphaUShort.createCompatibleSampleModel(1, 1))));
}
@Test
public void canEncodeImageRGB() {
assertTrue(spi.canEncodeImage(new BufferedImage(1, 1, BufferedImage.TYPE_3BYTE_BGR)));
assertTrue(spi.canEncodeImage(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR)));
assertTrue(spi.canEncodeImage(new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB)));
assertTrue(spi.canEncodeImage(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB)));
assertTrue(spi.canEncodeImage(new BufferedImage(1, 1, BufferedImage.TYPE_INT_BGR)));
assertTrue(spi.canEncodeImage(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_BGR)));
}
@Test
public void canNotEncodeImageARGB() {
assertFalse(spi.canEncodeImage(new BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR)));
assertFalse(spi.canEncodeImage(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR)));
assertFalse(spi.canEncodeImage(new BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR_PRE)));
assertFalse(spi.canEncodeImage(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR_PRE)));
assertFalse(spi.canEncodeImage(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB)));
assertFalse(spi.canEncodeImage(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB)));
assertFalse(spi.canEncodeImage(new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB_PRE)));
assertFalse(spi.canEncodeImage(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB_PRE)));
}
@Test
public void canNotEncodeImageNonGrayOrRGB() {
ComponentColorModel xyzByte = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_CIEXYZ), false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
assertFalse(spi.canEncodeImage(new ImageTypeSpecifier(xyzByte, xyzByte.createCompatibleSampleModel(1, 1))));
ComponentColorModel xyzUshort = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_CIEXYZ), false, false, Transparency.OPAQUE, DataBuffer.TYPE_USHORT);
assertFalse(spi.canEncodeImage(new ImageTypeSpecifier(xyzUshort, xyzUshort.createCompatibleSampleModel(1, 1))));
}
} }

Some files were not shown because too many files have changed in this diff Show More