Compare commits

..

52 Commits

Author SHA1 Message Date
Harald Kuhr 26d3de45a7 [maven-release-plugin] prepare for next development iteration 2020-01-09 19:40:24 +01:00
Harald Kuhr 13507ce303 [maven-release-plugin] prepare release twelvemonkeys-3.4.3 2020-01-09 19:40:16 +01:00
Harald Kuhr a8508dc234 Stick to the git user, when using ssh
(cherry picked from commit b6aec25f00)
2020-01-09 19:28:35 +01:00
Harald Kuhr b3cf467f0b log4j removal
(cherry picked from commit ae213dcf5e)
2020-01-09 19:25:48 +01:00
Harald Kuhr b0e6fbed9f #510: Fixes possible hang situation
(cherry picked from commit 5501c0e709)
2020-01-09 19:25:48 +01:00
Harald Kuhr c087addb76 #501: Fix for TYPE_USHORT_555/565_RGB, ColorModel now 16 bits
(cherry picked from commit 42e17f2063)
2020-01-09 19:25:48 +01:00
Harald Kuhr 250c58cc2e #289, #493: Finally implemented subsampling for < 8 bit samples
(cherry picked from commit 0c2433dc9f)
2020-01-09 19:25:48 +01:00
Oliver Schmidtmer c33b3a76f4 Test correction for ViewBox based svg sizes
(cherry picked from commit 810b7197ab)
2020-01-09 19:24:58 +01:00
Oliver Schmidtmer f14e6823bd When rescaling SVGs use the ViewBox, if defined, for default sizes
(cherry picked from commit 24a0786d64)
2020-01-09 19:24:58 +01:00
Harald Kuhr cae72336a2 [maven-release-plugin] prepare for next development iteration 2019-08-12 21:05:55 +02:00
Harald Kuhr c5bf0a6f0b [maven-release-plugin] prepare release twelvemonkeys-3.4.2 2019-08-12 21:03:23 +02:00
Harald Kuhr 691b7560db Switched Maven SCM to use ssh.
(cherry picked from commit c1834dc78d)
2019-08-12 20:42:24 +02:00
Harald Kuhr e1025f9540 Fixed JavaDoc errors to enable Java 8 build.
(cherry picked from commit 9e23413456)
2019-08-10 00:58:08 +02:00
Harald Kuhr fa09099da0 Fixed encoding issues in readme.
(cherry picked from commit 7d2c692663)
2019-08-09 21:04:41 +02:00
Harald Kuhr 140b074ac6 #398: Better exception message when BufferedImage size > Integer.MAX
(cherry picked from commit 9ce1a86cae)
2019-08-09 21:04:41 +02:00
Harald Kuhr 59c6c18cbb #477: Better tests to for cyclic loops in IFDs.
(cherry picked from commit b0b5de5fa4)
2019-08-09 21:04:41 +02:00
Harald Kuhr c48e17dabf #474: Fix java.awt.color.CMMException: Can not access specified profile
(cherry picked from commit 64178bd636)
2019-08-09 21:04:41 +02:00
Harald Kuhr 22a842eb78 449# Missing test to verify that we ignore bogus 0 byte counts.
(cherry picked from commit 7985cdd4a7)
2019-08-09 21:04:41 +02:00
Harald Kuhr bdd7f5b228 #492: Now correctly parses multiple strings for ASCII fields.
(cherry picked from commit 8247861095)
2019-08-09 21:04:40 +02:00
Harald Kuhr 0e41d4a5f7 #477: Avoid cyclic loops in IFDs.
(cherry picked from commit 8480c929c1)
2019-08-09 21:04:40 +02:00
Harald Kuhr 653360e054 Moving travis build to trusty, to fix JDK8 build
(cherry picked from commit e6f437f55b)
2019-08-09 21:04:40 +02:00
Harald Kuhr 4f193d543c #488: Fix for AIOOBE in getEmbeddedICCProfile when ICC profile is empty
(cherry picked from commit ee049d9465)
2019-08-09 21:04:40 +02:00
Harald Kuhr 1d0cc43476 #489 Fix for Unexpected End of PackBits Stream for padded streams.
(cherry picked from commit f6aa810f8b)
2019-08-09 21:04:40 +02:00
Harald Kuhr 9791a251ed #469 Fix for OOME while reading Exif with corrupted IFDs/counts
(cherry picked from commit e8d1b999a2)
2019-08-09 21:04:40 +02:00
Harald Kuhr 0bc30f4d18 JPEG Exif parsing optimization.
(cherry picked from commit d7fbd6594e)
2019-08-09 21:04:40 +02:00
Harald Kuhr 022fc03fbb XMLSerializer speedup.
(cherry picked from commit caef9b6a9e)
2019-08-09 21:04:39 +02:00
Harald Kuhr 8b66842859 #475: Fix support for writing TIFF > 2 GB
(cherry picked from commit 7fad4d5cd8)
2019-08-09 21:04:39 +02:00
Harald Kuhr 5251f4665e #473: Fix for ColorMap (Indexed) TIFF with non-alpha ExtraSamples.
(cherry picked from commit 3e4b14f984)
2019-08-09 21:04:39 +02:00
Paul Verest b98b81b877 colorize code snippets in README using GFM ``java, ``xml
(cherry picked from commit 51b0734462)
2019-08-09 21:03:01 +02:00
Harald Kuhr 774b494fec Updated commons-fileupload dependency to safe version, even if in scope provided, just in case.
(cherry picked from commit 8e3cd5aedb)
2019-08-09 21:03:00 +02:00
Oliver Schmidtmer 90ef605b0c Fix for #455: Ignore profiles PhotometricInterpretation MinIsWhite with 1bit/pixel
(cherry picked from commit cbaa0dc688)
2019-08-09 21:03:00 +02:00
Harald Kuhr b40eea0fc4 Fix test case for #446 in case of "Gerenic CMYK" profile not being available.
(cherry picked from commit 61bac97933)
2019-08-09 21:03:00 +02:00
Harald Kuhr 9ac2013965 Better assertion failed messages.
(cherry picked from commit 3e9be32279)
2019-08-09 21:03:00 +02:00
Harald Kuhr 4740a39cd2 Test case for #446.
(cherry picked from commit a0955875d8)
2019-08-09 21:03:00 +02:00
Harald Kuhr 7ebcc437c3 Various Java 9 and beyond fixes:
- ExtraSamplesColorModel now overrides getComponentSize for correct size
 - TIFFImageReader/WriterSpi now recognizes the JEP 262 TIFF plugin
 - CCITTFaxEncoderStreamTest now directly creates writer (not JDK one)

(cherry picked from commit 7e0de14783)
2019-08-09 21:02:30 +02:00
Harald Kuhr 70c16dfdd9 Various Java 9 and beyond fixes.
(cherry picked from commit de34d4642e)
2019-08-09 21:02:30 +02:00
Harald Kuhr c9e2e21727 Equals method for DiscreteAlphaIndexColorModel, needed for Java 10.
(cherry picked from commit b86bad2bf9)
2019-08-09 21:02:30 +02:00
Harald Kuhr 230ac33283 #442 SVG BaseURI issue fix
(cherry picked from commit cc5af0134c)
2019-08-09 21:02:30 +02:00
Bernhard Fey 66e0acb668 Added test file for non-alpha extra channel
Added test file for CMYK TIFF with non-alpha extra channel

(cherry picked from commit edcac25f5e)
2019-08-09 21:02:30 +02:00
Bernhard Fey 7d8858c177 Modified new create[ImageTypeSpecifier] method according to suggestions by @haraldk
Renamed "create" method to "createImageTypeSpecifier".
Added exception thrown for unsupported planarConfiguration values.

(cherry picked from commit 5a5c1f996b)
2019-08-09 21:02:30 +02:00
Bernhard Fey faab9517dd Fix for non-RGB images with extra sample
Added "create" method to TIFFImageReader that centralizes the use of "createBanded" and "createInterleaved" as well as the "extra samples" special case and fixes non-RGB images with non-alpha extra samples

(cherry picked from commit f9b8cae0ea)
2019-08-09 21:02:30 +02:00
Harald Kuhr 2433777b6d Updated readme
(cherry picked from commit 62538c3db9)
2019-08-09 21:02:13 +02:00
Harald Kuhr 3980c937cf Fixed release date.
(cherry picked from commit 48aa504be4)
2019-08-09 21:02:13 +02:00
Harald Kuhr 468ffb891d Updated versions from 3.4 to 3.4.1.
(cherry picked from commit ed2eb7642a)
2019-08-09 21:02:13 +02:00
Harald Kuhr e27e8a7ccb #408 Added servlet JAR to dependency example.
(cherry picked from commit 24ec5ae34d)
2019-08-09 21:02:03 +02:00
Harald Kuhr f2dba604da #311 Updated some more license headers that was left out in the initial change.
(cherry picked from commit a7b374e51a)
2019-08-09 21:01:29 +02:00
Harald Kuhr 04f27a1694 #438 CompoundDocument file descriptor fix 2018-09-08 16:21:01 +02:00
Harald Kuhr 2630a6a795 [maven-release-plugin] prepare for next development iteration 2018-09-07 19:48:17 +02:00
Harald Kuhr ab2f1f7e91 [maven-release-plugin] prepare release twelvemonkeys-3.4.1 2018-09-07 19:48:10 +02:00
Harald Kuhr 7110e89bda Prepare next release 2018-09-07 19:42:06 +02:00
Harald Kuhr a06cbfd6f4 #437 Catching exception from static init, prints a warning and moves on.
(cherry picked from commit d8d0131)
2018-08-30 15:04:55 +02:00
Harald Kuhr 3b68d676f3 #439: Unclear exception message when passing image metadata as stream metadata
(cherry picked from commit 6018093)
2018-08-30 15:04:52 +02:00
117 changed files with 1157 additions and 5006 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
BSD 3-Clause License
Copyright (c) 2008-2020, Harald Kuhr
Copyright (c) 2017, Harald Kuhr
All rights reserved.
Redistribution and use in source and binary forms, with or without
+33 -33
View File
@@ -2,7 +2,7 @@
Master branch build status: [![Build Status](https://travis-ci.org/haraldk/TwelveMonkeys.svg?branch=master)](https://travis-ci.org/haraldk/TwelveMonkeys)
Latest release is TwelveMonkeys ImageIO [3.4.3](https://search.maven.org/search?q=g:com.twelvemonkeys.imageio%20AND%20v:3.4.3) (Jan. 9th, 2020).
Latest release is TwelveMonkeys ImageIO [3.4.1](https://search.maven.org/search?q=g:com.twelvemonkeys.imageio%20AND%20v:3.4.1) (Sep. 7th, 2018).
[Release notes](https://github.com/haraldk/TwelveMonkeys/releases/latest).
## About
@@ -494,12 +494,12 @@ To depend on the JPEG and TIFF plugin using Maven, add the following to your POM
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-jpeg</artifactId>
<version>3.4.3</version>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-tiff</artifactId>
<version>3.4.3</version>
<version>3.4.1</version>
</dependency>
<!--
@@ -509,7 +509,7 @@ To depend on the JPEG and TIFF plugin using Maven, add the following to your POM
<dependency>
<groupId>com.twelvemonkeys.servlet</groupId>
<artifactId>servlet</artifactId>
<version>3.4.3</version>
<version>3.4.1</version>
</dependency>
</dependencies>
```
@@ -518,52 +518,52 @@ To depend on the JPEG and TIFF plugin using Maven, add the following to your POM
To depend on the JPEG and TIFF plugin in your IDE or program, add all of the following JARs to your class path:
twelvemonkeys-common-lang-3.4.3.jar
twelvemonkeys-common-io-3.4.3.jar
twelvemonkeys-common-image-3.4.3.jar
twelvemonkeys-imageio-core-3.4.3.jar
twelvemonkeys-imageio-metadata-3.4.3.jar
twelvemonkeys-imageio-jpeg-3.4.3.jar
twelvemonkeys-imageio-tiff-3.4.3.jar
twelvemonkeys-common-lang-3.4.1.jar
twelvemonkeys-common-io-3.4.1.jar
twelvemonkeys-common-image-3.4.1.jar
twelvemonkeys-imageio-core-3.4.1.jar
twelvemonkeys-imageio-metadata-3.4.1.jar
twelvemonkeys-imageio-jpeg-3.4.1.jar
twelvemonkeys-imageio-tiff-3.4.1.jar
### Links to prebuilt binaries
##### Latest version (3.4.3)
##### Latest version (3.4.1)
Requires Java 7 or later.
Common dependencies
* [common-lang-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-lang/3.4.3/common-lang-3.4.3.jar)
* [common-io-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-io/3.4.3/common-io-3.4.3.jar)
* [common-image-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-image/3.4.3/common-image-3.4.3.jar)
* [common-lang-3.4.1.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-lang/3.4.1/common-lang-3.4.1.jar)
* [common-io-3.4.1.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-io/3.4.1/common-io-3.4.1.jar)
* [common-image-3.4.1.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/common/common-image/3.4.1/common-image-3.4.1.jar)
ImageIO dependencies
* [imageio-core-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-core/3.4.3/imageio-core-3.4.3.jar)
* [imageio-metadata-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-metadata/3.4.3/imageio-metadata-3.4.3.jar)
* [imageio-core-3.4.1.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-core/3.4.1/imageio-core-3.4.1.jar)
* [imageio-metadata-3.4.1.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-metadata/3.4.1/imageio-metadata-3.4.1.jar)
ImageIO plugins
* [imageio-bmp-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-bmp/3.4.3/imageio-bmp-3.4.3.jar)
* [imageio-jpeg-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jpeg/3.4.3/imageio-jpeg-3.4.3.jar)
* [imageio-tiff-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tiff/3.4.3/imageio-tiff-3.4.3.jar)
* [imageio-pnm-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pnm/3.4.3/imageio-pnm-3.4.3.jar)
* [imageio-psd-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-psd/3.4.3/imageio-psd-3.4.3.jar)
* [imageio-hdr-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-hdr/3.4.3/imageio-hdr-3.4.3.jar)
* [imageio-iff-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-iff/3.4.3/imageio-iff-3.4.3.jar)
* [imageio-pcx-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pcx/3.4.3/imageio-pcx-3.4.3.jar)
* [imageio-pict-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pict/3.4.3/imageio-pict-3.4.3.jar)
* [imageio-sgi-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-sgi/3.4.3/imageio-sgi-3.4.3.jar)
* [imageio-tga-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tga/3.4.3/imageio-tga-3.4.3.jar)
* [imageio-icns-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-icns/3.4.3/imageio-icns-3.4.3.jar)
* [imageio-thumbsdb-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-thumbsdb/3.4.3/imageio-thumbsdb-3.4.3.jar)
* [imageio-bmp-3.4.1.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-bmp/3.4.1/imageio-bmp-3.4.1.jar)
* [imageio-jpeg-3.4.1.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-jpeg/3.4.1/imageio-jpeg-3.4.1.jar)
* [imageio-tiff-3.4.1.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tiff/3.4.1/imageio-tiff-3.4.1.jar)
* [imageio-pnm-3.4.1.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pnm/3.4.1/imageio-pnm-3.4.1.jar)
* [imageio-psd-3.4.1.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-psd/3.4.1/imageio-psd-3.4.1.jar)
* [imageio-hdr-3.4.1.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-hdr/3.4.1/imageio-hdr-3.4.1.jar)
* [imageio-iff-3.4.1.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-iff/3.4.1/imageio-iff-3.4.1.jar)
* [imageio-pcx-3.4.1.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pcx/3.4.1/imageio-pcx-3.4.1.jar)
* [imageio-pict-3.4.1.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-pict/3.4.1/imageio-pict-3.4.1.jar)
* [imageio-sgi-3.4.1.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-sgi/3.4.1/imageio-sgi-3.4.1.jar)
* [imageio-tga-3.4.1.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-tga/3.4.1/imageio-tga-3.4.1.jar)
* [imageio-icns-3.4.1.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-icns/3.4.1/imageio-icns-3.4.1.jar)
* [imageio-thumbsdb-3.4.1.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-thumbsdb/3.4.1/imageio-thumbsdb-3.4.1.jar)
ImageIO plugins requiring 3rd party libs
* [imageio-batik-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-batik/3.4.3/imageio-batik-3.4.3.jar)
* [imageio-batik-3.4.1.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-batik/3.4.1/imageio-batik-3.4.1.jar)
Photoshop Path support for ImageIO
* [imageio-clippath-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-clippath/3.4.3/imageio-clippath-3.4.3.jar)
* [imageio-clippath-3.4.1.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/imageio/imageio-clippath/3.4.1/imageio-clippath-3.4.1.jar)
Servlet support
* [servlet-3.4.3.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/servlet/servlet/3.4.3/servlet-3.4.3.jar)
* [servlet-3.4.1.jar](http://search.maven.org/remotecontent?filepath=com/twelvemonkeys/servlet/servlet/3.4.1/servlet-3.4.1.jar)
##### Old version (3.0.x)
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>com.twelvemonkeys</groupId>
<artifactId>twelvemonkeys</artifactId>
<version>3.5</version>
<version>3.4.4-SNAPSHOT</version>
</parent>
<groupId>com.twelvemonkeys.bom</groupId>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.common</groupId>
<artifactId>common</artifactId>
<version>3.5</version>
<version>3.4.4-SNAPSHOT</version>
</parent>
<artifactId>common-image</artifactId>
<packaging>jar</packaging>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.common</groupId>
<artifactId>common</artifactId>
<version>3.5</version>
<version>3.4.4-SNAPSHOT</version>
</parent>
<artifactId>common-io</artifactId>
<packaging>jar</packaging>
@@ -922,7 +922,7 @@ public final class FileUtil {
// A URL should never be able to represent an opaque URI, test anyway
throw new IllegalArgumentException("URI is not hierarchical");
}
if (path.isEmpty()) {
if (path.equals("")) {
throw new IllegalArgumentException("URI path component is empty");
}
@@ -33,12 +33,12 @@ package com.twelvemonkeys.io.ole2;
import com.twelvemonkeys.io.InputStreamAbstractTest;
import com.twelvemonkeys.io.LittleEndianDataOutputStream;
import com.twelvemonkeys.io.MemoryCacheSeekableStream;
import com.twelvemonkeys.io.SeekableInputStream;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Arrays;
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.common</groupId>
<artifactId>common</artifactId>
<version>3.5</version>
<version>3.4.4-SNAPSHOT</version>
</parent>
<artifactId>common-lang</artifactId>
<packaging>jar</packaging>
@@ -88,7 +88,7 @@ public final class BeanUtil {
while (begIdx < pProperty.length() && begIdx >= 0) {
endIdx = pProperty.indexOf('.', endIdx + 1);
endIdx = pProperty.indexOf(".", endIdx + 1);
if (endIdx > 0) {
subProp = pProperty.substring(begIdx, endIdx);
begIdx = endIdx + 1;
@@ -106,7 +106,7 @@ public final class BeanUtil {
Class[] paramClass = new Class[0];
int begBracket;
if ((begBracket = subProp.indexOf('[')) > 0) {
if ((begBracket = subProp.indexOf("[")) > 0) {
// An error if there is no matching bracket
if (!subProp.endsWith("]")) {
return null;
@@ -622,7 +622,7 @@ public class WildcardStringParser {
buffer.append("\n");
buffer.append(" Format: <state index>: <character> (<last free state>)");
buffer.append("\n");
buffer.append(" Number of strings parsed: ").append(totalNumberOfStringsParsed);
buffer.append(" Number of strings parsed: " + totalNumberOfStringsParsed);
buffer.append("\n");
}
return buffer.toString();
@@ -1122,7 +1122,7 @@ public abstract class CollectionAbstractTest extends ObjectAbstractTest {
resetEmpty();
Object[] a = new Object[] { new Object(), null, null };
Object[] array = collection.toArray(a);
assertArrayEquals("Given array shouldn't shrink", array, a);
assertEquals("Given array shouldn't shrink", array, a);
assertEquals("Last element should be set to null", a[0], null);
verifyAll();
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys</groupId>
<artifactId>twelvemonkeys</artifactId>
<version>3.5</version>
<version>3.4.4-SNAPSHOT</version>
</parent>
<groupId>com.twelvemonkeys.common</groupId>
<artifactId>common</artifactId>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys</groupId>
<artifactId>twelvemonkeys</artifactId>
<version>3.5</version>
<version>3.4.4-SNAPSHOT</version>
</parent>
<groupId>com.twelvemonkeys.contrib</groupId>
<artifactId>contrib</artifactId>
@@ -45,9 +45,11 @@ import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.*;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
@@ -356,21 +358,13 @@ public final class TIFFUtilities {
}
}
int compression = -1;
Entry compressionEntry = IFD.getEntryById(TIFF.TAG_COMPRESSION);
if (compressionEntry != null && compressionEntry.getValue() instanceof Number) {
compression = ((Number) compressionEntry.getValue()).shortValue();
}
boolean rearrangedByteStrips = false;
Entry oldJpegData = IFD.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT);
Entry oldJpegDataLength = IFD.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
long[] jpegByteCounts = null;
long[] jpegOffsets = null;
if (oldJpegData != null && oldJpegData.valueCount() > 0) {
// convert JPEGInterchangeFormat to new-style-JPEG
jpegByteCounts = new long[0];
jpegOffsets = getValueAsLongArray(oldJpegData);
long[] jpegByteCounts = new long[0];
long[] jpegOffsets = getValueAsLongArray(oldJpegData);
if (oldJpegDataLength != null && oldJpegDataLength.valueCount() > 0) {
jpegByteCounts = getValueAsLongArray(oldJpegDataLength);
}
@@ -394,20 +388,6 @@ public final class TIFFUtilities {
newIFD.remove(oldJpegDataLength);
rearrangedByteStrips = true;
}
else if (offsets.length == 1 && oldJpegDataLength != null && (jpegOffsets[0] < offsets[0]) && (jpegOffsets[0] + jpegByteCounts[0]) > (offsets[0] + byteCounts[0])) {
// ByteStrip contains only a part of JPEGInterchangeFormat
newOffsets = writeData(jpegOffsets, jpegByteCounts, outputStream);
newIFD.remove(stripOffsetsEntry);
newIFD.add(new TIFFEntry(useTiles ? TIFF.TAG_TILE_OFFSETS : TIFF.TAG_STRIP_OFFSETS, newOffsets));
newIFD.remove(stripByteCountsEntry);
newIFD.add(new TIFFEntry(useTiles ? TIFF.TAG_TILE_BYTE_COUNTS : TIFF.TAG_STRIP_BYTE_COUNTS, new int[]{(int) (jpegByteCounts[0])}));
newIFD.remove(oldJpegData);
newIFD.remove(oldJpegDataLength);
rearrangedByteStrips = true;
}
else if (oldJpegDataLength != null) {
// multiple bytestrips
// search for SOF on first strip and copy to each if needed
@@ -443,7 +423,7 @@ public final class TIFFUtilities {
byte[] buffer = new byte[(int) byteCounts[i]];
newByteCounts[i] = (int) (jpegInterchangeData.length + byteCounts[i]);
stream.readFully(buffer);
if (buffer[0] != ((byte) 0xff) || buffer[1] != ((byte) 0xda)) {
if (buffer[0] != 0xff && buffer[1] != 0xda) {
outputStream.write(sosMarker);
newByteCounts[i] += sosMarker.length;
}
@@ -460,58 +440,7 @@ public final class TIFFUtilities {
rearrangedByteStrips = true;
}
}
else if (compression == TIFFExtension.COMPRESSION_OLD_JPEG) {
// old-style but no JPEGInterchangeFormat
long[] yCbCrSubSampling = getValueAsLongArray(IFD.getEntryById(TIFF.TAG_YCBCR_SUB_SAMPLING));
int subsampling = yCbCrSubSampling != null
? (int) ((yCbCrSubSampling[0] & 0xf) << 4 | yCbCrSubSampling[1] & 0xf)
: 0x22;
int bands = ((Number) IFD.getEntryById(TIFF.TAG_SAMPLES_PER_PIXEL).getValue()).intValue();
int w = ((Number) IFD.getEntryById(TIFF.TAG_IMAGE_WIDTH).getValue()).intValue();
int h = ((Number) IFD.getEntryById(TIFF.TAG_IMAGE_HEIGHT).getValue()).intValue();
int r = ((Number) (useTiles ? IFD.getEntryById(TIFF.TAG_TILE_HEIGTH) : IFD.getEntryById(TIFF.TAG_ROWS_PER_STRIP)).getValue()).intValue();
int c = useTiles ? ((Number) IFD.getEntryById(TIFF.TAG_TILE_WIDTH).getValue()).intValue() : w;
newOffsets = new int[offsets.length];
int[] newByteCounts = new int[byteCounts.length];
// No JPEGInterchangeFormat
for (int i = 0; i < offsets.length; i++) {
byte[] start = new byte[2];
stream.seek(offsets[i]);
stream.readFully(start);
newOffsets[i] = (int) outputStream.getStreamPosition();
if (start[0] == ((byte) 0xff) && start[1] == ((byte) 0xd8)) {
// full image stream, nothing to do
writeData(stream, outputStream, offsets[i], byteCounts[i]);
}
else if (start[0] == ((byte) 0xff) && start[1] == ((byte) 0xda)) {
// starts with SOS
outputStream.writeShort(JPEG.SOI);
writeSOF0(outputStream, bands, c, r, subsampling);
writeData(stream, outputStream, offsets[i], byteCounts[i]);
outputStream.writeShort(JPEG.EOI);
}
else {
// raw data
outputStream.writeShort(JPEG.SOI);
writeSOF0(outputStream, bands, c, r, subsampling);
writeSOS(outputStream, bands);
writeData(stream, outputStream, offsets[i], byteCounts[i]);
outputStream.writeShort(JPEG.EOI);
}
newByteCounts[i] = ((int) outputStream.getStreamPosition()) - newOffsets[i];
}
newIFD.remove(stripOffsetsEntry);
newIFD.add(new TIFFEntry(useTiles ? TIFF.TAG_TILE_OFFSETS : TIFF.TAG_STRIP_OFFSETS, newOffsets));
newIFD.remove(stripByteCountsEntry);
newIFD.add(new TIFFEntry(useTiles ? TIFF.TAG_TILE_BYTE_COUNTS : TIFF.TAG_STRIP_BYTE_COUNTS, newByteCounts));
rearrangedByteStrips = true;
}
if (!rearrangedByteStrips && stripOffsetsEntry != null && stripByteCountsEntry != null) {
newOffsets = writeData(offsets, byteCounts, outputStream);
@@ -528,21 +457,12 @@ public final class TIFFUtilities {
oldJpegTableQ = IFD.getEntryById(TIFF.TAG_OLD_JPEG_Q_TABLES);
oldJpegTableDC = IFD.getEntryById(TIFF.TAG_OLD_JPEG_DC_TABLES);
oldJpegTableAC = IFD.getEntryById(TIFF.TAG_OLD_JPEG_AC_TABLES);
if ((oldJpegTableQ != null) || (oldJpegTableDC != null) || (oldJpegTableAC != null)) {
if (oldJpegTableQ != null || oldJpegTableDC != null || oldJpegTableAC != null) {
if (IFD.getEntryById(TIFF.TAG_JPEG_TABLES) != null) {
throw new IOException("Found old-style and new-style JPEGTables");
}
boolean tablesInStream = jfifContainsTables(oldJpegTableQ, jpegOffsets, jpegByteCounts);
tablesInStream &= jfifContainsTables(oldJpegTableDC, jpegOffsets, jpegByteCounts);
tablesInStream &= jfifContainsTables(oldJpegTableAC, jpegOffsets, jpegByteCounts);
if (!tablesInStream) {
// merge them only to JPEGTables if they are not already contained within the stream
Entry jpegTables = mergeTables(oldJpegTableQ, oldJpegTableDC, oldJpegTableAC);
if (jpegTables != null) {
newIFD.add(jpegTables);
}
}
newIFD.add(mergeTables(oldJpegTableQ, oldJpegTableDC, oldJpegTableAC));
if (oldJpegTableQ != null) {
newIFD.remove(oldJpegTableQ);
}
@@ -554,66 +474,17 @@ public final class TIFFUtilities {
}
}
if (compressionEntry != null && compression == TIFFExtension.COMPRESSION_OLD_JPEG) {
newIFD.remove(compressionEntry);
newIFD.add(new TIFFEntry(TIFF.TAG_COMPRESSION, TIFF.TYPE_SHORT, TIFFExtension.COMPRESSION_JPEG));
Entry compressionEntry = IFD.getEntryById(TIFF.TAG_COMPRESSION);
if(compressionEntry != null) {
Number compression = (Number) compressionEntry.getValue();
if (compression.shortValue() == TIFFExtension.COMPRESSION_OLD_JPEG) {
newIFD.remove(compressionEntry);
newIFD.add(new TIFFEntry(TIFF.TAG_COMPRESSION, TIFF.TYPE_SHORT, TIFFExtension.COMPRESSION_JPEG));
}
}
return newIFD;
}
//TODO merge/extract from TIFFReader Jpeg/6 stream reconstruction
private void writeSOF0(ImageOutputStream outputStream, int bands, int width, int height, int subsampling) throws IOException {
outputStream.writeShort(JPEG.SOF0); // TODO: Use correct process for data
outputStream.writeShort(2 + 6 + 3 * bands); // SOF0 len
outputStream.writeByte(8); // bits TODO: Consult raster/transfer type or BitsPerSample for 12/16 bits support
outputStream.writeShort(height); // height
outputStream.writeShort(width); // width
outputStream.writeByte(bands); // Number of components
for (int comp = 0; comp < bands; comp++) {
outputStream.writeByte(comp); // Component id
outputStream.writeByte(comp == 0 ? subsampling : 0x11); // h/v subsampling
outputStream.writeByte(comp); // Q table selector TODO: Consider merging if tables are equal, correct selection if only 1 or 2 valid tables are contained
}
}
//TODO merge/extract from TIFFReader Jpeg/6 stream reconstruction
private void writeSOS(ImageOutputStream outputStream, int bands) throws IOException {
outputStream.writeShort(JPEG.SOS);
outputStream.writeShort(6 + 2 * bands); // SOS length
outputStream.writeByte(bands); // Num comp
for (int component = 0; component < bands; component++) {
outputStream.writeByte(component); // Comp id
outputStream.writeByte(component == 0 ? component : 0x10 + (component & 0xf)); // dc/ac selector TODO: correct selection if only 1 or 2 valid tables are contained
}
outputStream.writeByte(0); // Spectral selection start
outputStream.writeByte(0); // Spectral selection end
outputStream.writeByte(0); // Approx high & low
}
private void writeData(ImageInputStream input, ImageOutputStream output, long offset, long length) throws IOException {
input.seek(offset);
byte[] buffer = new byte[(int) length];
stream.readFully(buffer);
output.write(buffer);
}
private boolean jfifContainsTables(Entry tableEntry, long[] jpegOffsets, long[] jpegLengths) throws IOException {
if (jpegLengths == null || jpegOffsets == null || jpegLengths.length == 0) return false;
if (tableEntry != null) {
long[] tableOffsets = getValueAsLongArray(tableEntry);
for (long offset : tableOffsets) {
if (offset < jpegOffsets[0] || offset > (jpegOffsets[0] + jpegLengths[0])) {
return false;
}
}
}
return true;
}
//TODO merge/extract from TIFFReader Jpeg/6 stream reconstruction
private Entry mergeTables(Entry qEntry, Entry dcEntry, Entry acEntry) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
@@ -623,16 +494,12 @@ public final class TIFFUtilities {
long[] off = getValueAsLongArray(qEntry);
byte[] table = new byte[64];
for (int tableId = 0; tableId < off.length; tableId++) {
try {
stream.seek(off[tableId]);
stream.readFully(table);
dos.writeShort(JPEG.DQT);
dos.writeShort(3 + 64);
dos.writeByte(tableId);
dos.write(table);
} catch (EOFException e) {
// invalid table pointer, ignore
}
stream.seek(off[tableId]);
stream.readFully(table);
dos.writeShort(JPEG.DQT);
dos.writeShort(3 + 64);
dos.writeByte(tableId);
dos.write(table);
}
}
@@ -640,50 +507,30 @@ public final class TIFFUtilities {
if (dcEntry != null && dcEntry.valueCount() > 0) {
long[] off = getValueAsLongArray(dcEntry);
for (int tableId = 0; tableId < off.length; tableId++) {
try {
stream.seek(off[tableId]);
byte[] table = readHUFFTable();
if (table.length > (16 + 17)) {
// to long, table is invalid, just ignoe
continue;
}
dos.writeShort(JPEG.DHT);
dos.writeShort(3 + table.length);
dos.writeByte(tableId);
dos.write(table);
} catch (EOFException e) {
// invalid table pointer, ignore
}
stream.seek(off[tableId]);
byte[] table = readHUFFTable();
dos.writeShort(JPEG.DHT);
dos.writeShort(3 + table.length);
dos.writeByte(tableId);
dos.write(table);
}
}
if (acEntry != null && acEntry.valueCount() > 0) {
long[] off = getValueAsLongArray(acEntry);
for (int tableId = 0; tableId < off.length; tableId++) {
try {
stream.seek(off[tableId]);
byte[] table = readHUFFTable();
if (table.length > (16 + 256)) {
// to long, table is invalid, just ignoe
continue;
}
dos.writeShort(JPEG.DHT);
dos.writeShort(3 + table.length);
dos.writeByte(16 | tableId);
dos.write(table);
} catch (EOFException e) {
// invalid table pointer, ignore
}
stream.seek(off[tableId]);
byte[] table = readHUFFTable();
dos.writeShort(JPEG.DHT);
dos.writeShort(3 + table.length);
dos.writeByte(16 | tableId);
dos.write(table);
}
}
dos.writeShort(JPEG.EOI);
bos.close();
if (bos.size() == 4) {
// no valid tables, don't add
return null;
}
return new TIFFEntry(TIFF.TAG_JPEG_TABLES, TIFF.TYPE_UNDEFINED, bos.toByteArray());
}
@@ -693,11 +540,15 @@ public final class TIFFUtilities {
stream.readFully(lengths);
int numCodes = 0;
for (int i = 0; i < lengths.length; i++) {
numCodes += ((int) lengths[i]) & 0xff;
numCodes += lengths[i];
}
byte table[] = new byte[16 + numCodes];
System.arraycopy(lengths, 0, table, 0, 16);
stream.readFully(table, 16, numCodes);
int off = 16;
for (int i = 0; i < lengths.length; i++) {
stream.read(table, off, lengths[i]);
off += lengths[i];
}
return table;
}
@@ -708,11 +559,7 @@ public final class TIFFUtilities {
stream.seek(offsets[i]);
byte[] buffer = new byte[(int) byteCounts[i]];
try {
stream.readFully(buffer);
} catch (EOFException e) {
// invalid strip length
}
stream.readFully(buffer);
outputStream.write(buffer);
}
return newOffsets;
@@ -724,7 +571,7 @@ public final class TIFFUtilities {
if (entry.valueCount() == 1) {
// For single entries, this will be a boxed type
value = new long[]{((Number) entry.getValue()).longValue()};
value = new long[] {((Number) entry.getValue()).longValue()};
}
else if (entry.getValue() instanceof short[]) {
short[] shorts = (short[]) entry.getValue();
@@ -202,39 +202,36 @@ public class TIFFUtilitiesTest {
}
@Test
public void testOldStyleJPEGTransform() throws IOException {
String[] testFiles = new String[]{
public void testMergeBogusInterchangeFormatLength() throws IOException {
String[] testFiles = new String[] {
"/tiff/old-style-jpeg-bogus-jpeginterchangeformatlength.tif", // InterchangeFormat before StripOffset, length not including StripOffset
"/tiff/old-style-jpeg-no-jpeginterchangeformatlength.tif", // missing JPEGInterChangeFormatLength and JPEGInterchangeFormat == StipOffset
"/tiff/old-style-jpeg-multiple-strips.tif", // InterchangeFormat with multiple strips
"/contrib/tiff/old-style-jpeg-invalid-tables.tif", // AC/DC Tables are invalid (to long) and lie within the JPEGInterchangeFormat stream
"/contrib/tiff/smallliz.tif", // InterchangeFormat contains whole JPEG, ByteStrip only raw ImageData after SOS
"/contrib/tiff/WangJPEG.tif", // multiple strips, first strip contains SOS
"/contrib/tiff/zackthecat.tif" // No JPEGInterchangeFormat, ByteStrip contains only raw image data
"/tiff/old-style-jpeg-multiple-strips.tif" // InterchangeFormat with multiple strips
};
for (String testFile : testFiles) {
try {
File output = File.createTempFile("imageiotest", ".tif");
ImageOutputStream outputStream = ImageIO.createImageOutputStream(output);
InputStream inputStream = getClassLoaderResource(testFile).openStream();
ImageInputStream imageInput = ImageIO.createImageInputStream(inputStream);
List<TIFFUtilities.TIFFPage> pages = TIFFUtilities.getPages(imageInput);
TIFFUtilities.writePages(outputStream, pages);
File output = File.createTempFile("imageiotest", ".tif");
ImageOutputStream outputStream = ImageIO.createImageOutputStream(output);
InputStream inputStream1 = getClassLoaderResource(testFile).openStream();
ImageInputStream imageInput1 = ImageIO.createImageInputStream(inputStream1);
InputStream inputStream2 = getClassLoaderResource(testFile).openStream();
ImageInputStream imageInput2 = ImageIO.createImageInputStream(inputStream2);
ArrayList<TIFFUtilities.TIFFPage> pages = new ArrayList<>();
pages.addAll(TIFFUtilities.getPages(imageInput1));
pages.addAll(TIFFUtilities.getPages(imageInput2));
TIFFUtilities.writePages(outputStream, pages);
ImageInputStream testOutput = ImageIO.createImageInputStream(output);
ImageReader reader = ImageIO.getImageReaders(testOutput).next();
reader.setInput(testOutput);
int numImages = reader.getNumImages(true);
for (int i = 0; i < numImages; i++) {
reader.read(i);
}
imageInput.close();
outputStream.close();
} catch (Exception exc) {
throw new IOException(testFile, exc);
ImageInputStream testOutput = ImageIO.createImageInputStream(output);
ImageReader reader = ImageIO.getImageReaders(testOutput).next();
reader.setInput(testOutput);
int numImages = reader.getNumImages(true);
for (int i = 0; i < numImages; i++) {
reader.read(i);
}
imageInput1.close();
imageInput2.close();
outputStream.close();
}
}
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.5</version>
<version>3.4.4-SNAPSHOT</version>
</parent>
<artifactId>imageio-batik</artifactId>
<name>TwelveMonkeys :: ImageIO :: Batik Plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.5</version>
<version>3.4.4-SNAPSHOT</version>
</parent>
<artifactId>imageio-bmp</artifactId>
<name>TwelveMonkeys :: ImageIO :: BMP plugin</name>
@@ -4,28 +4,26 @@
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
@@ -4,28 +4,26 @@
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
@@ -61,8 +59,8 @@ import java.util.Iterator;
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: BMPImageReader.java,v 1.0 Apr 20, 2009 11:54:28 AM haraldk Exp$
* @see ICOImageReader
* @version $Id: CURImageReader.java,v 1.0 Apr 20, 2009 11:54:28 AM haraldk Exp$
* @see com.twelvemonkeys.imageio.plugins.bmp.ICOImageReader
*/
public final class BMPImageReader extends ImageReaderBase {
private long pixelOffset;
@@ -614,7 +612,7 @@ public final class BMPImageReader extends ImageReaderBase {
}
// Why, oh why..? Instead of accepting it's own native format as it should,
// The DIBImageWriter only accepts instances of com.sun.imageio.plugins.bmp.BMPMetadata...
// The BMPImageWriter only accepts instances of com.sun.imageio.plugins.bmp.BMPMetadata...
// TODO: Consider reflectively construct a BMPMetadata and inject fields
return new BMPMetadata(header, colors);
}
@@ -4,28 +4,26 @@
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
@@ -1,150 +0,0 @@
/*
* Copyright (c) 2017, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriteParam;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.plugins.bmp.BMPImageWriteParam;
import javax.imageio.spi.ImageWriterSpi;
import javax.imageio.stream.ImageOutputStream;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.ByteOrder;
/**
* BMPImageWriter
*/
public final class BMPImageWriter extends DIBImageWriter {
protected BMPImageWriter(ImageWriterSpi provider) {
super(provider);
}
@Override
public ImageWriteParam getDefaultWriteParam() {
// We can use the existing BMPImageWriteParam, as it's part of the javax.imageio API.
return new BMPImageWriteParam(getLocale());
}
@Override
public IIOMetadata getDefaultImageMetadata(ImageTypeSpecifier imageType, ImageWriteParam param) {
// TODO
return null;
}
@Override
public IIOMetadata convertImageMetadata(IIOMetadata inData, ImageTypeSpecifier imageType, ImageWriteParam param) {
// TODO: Support both our own and the com.sun.. metadata + standard metadata
return null;
}
@Override
public void write(IIOMetadata streamMetadata, IIOImage image, ImageWriteParam param) throws IOException {
assertOutput();
if (image == null) {
throw new IllegalArgumentException("image may not be null");
}
if (image.hasRaster()) {
// TODO: The default BMPWriter seems to support this, consider doing so as well
throw new UnsupportedOperationException("image has a Raster!");
}
imageOutput.setByteOrder(ByteOrder.LITTLE_ENDIAN);
clearAbortRequest();
processImageStarted(0);
if (param == null) {
param = getDefaultWriteParam();
}
// Default to bottom-up
// TODO: top-down only allowed for RGB and BITFIELDS compressions (not RLE or PNG)!
// Though Windows seems to support top-down for RLE too...
final boolean isTopDown = param instanceof BMPImageWriteParam && ((BMPImageWriteParam) param).isTopDown();
// int compression = DIB.COMPRESSION_ALPHA_BITFIELDS; // BMP can use BIFTFIELDS or ALPHA_BITFIELDS
int compression = DIB.COMPRESSION_RGB;
// TODO: Fix
BufferedImage img = (BufferedImage) image.getRenderedImage();
int height = img.getHeight();
int width = img.getWidth();
// Write File header
// TODO: Always use V4/V5 header, when writing with alpha, to avoid ambiguity
// TODO: Allow writing normal BITMAP_INFO_HEADER_SIZE with "fake" alpha as well?
int infoHeaderSize = DIB.BITMAP_INFO_HEADER_SIZE;
boolean hasExtraMasks = infoHeaderSize == DIB.BITMAP_INFO_HEADER_SIZE && (compression == DIB.COMPRESSION_BITFIELDS || compression == DIB.COMPRESSION_ALPHA_BITFIELDS);
// TODO: Allow writing without file header for ICO/CUR support
writeFileHeader(infoHeaderSize, DIB.BMP_FILE_HEADER_SIZE + infoHeaderSize + width * height * 4, hasExtraMasks);
writeDIBHeader(infoHeaderSize, img.getWidth(), img.getHeight(), isTopDown, img.getColorModel().getPixelSize(), compression);
// writeDIBHeader(infoHeaderSize, img, isTopDown, DIB.COMPRESSION_RGB);
if (hasExtraMasks) {
imageOutput.writeInt(0x000000FF); // B
imageOutput.writeInt(0x0000FF00); // G
imageOutput.writeInt(0x00FF0000); // R
imageOutput.writeInt(0xFF000000); // A
}
writeUncompressed(isTopDown, img, height, width);
processImageComplete();
}
private void writeFileHeader(int infoHeaderSize, int fileSize, boolean hasMasks) throws IOException {
// 14 bytes
imageOutput.writeShort('M' << 8 | 'B');
imageOutput.writeInt(fileSize + (hasMasks ? 16 : 0)); // File size (only known at this time if uncompressed!)
imageOutput.writeShort(0); // Reserved
imageOutput.writeShort(0); // Reserved
imageOutput.writeInt(DIB.BMP_FILE_HEADER_SIZE + infoHeaderSize + (hasMasks ? 16 : 0)); // Offset to image data
}
public static void main(String[] args) throws IOException {
File input = new File(args[0]);
File output = new File(args[0].replace('.', '_') + "_copy.bmp");
try (ImageOutputStream stream = ImageIO.createImageOutputStream(output)) {
DIBImageWriter writer = new BMPImageWriter(null);
writer.setOutput(stream);
writer.write(ImageIO.read(input));
}
}
}
@@ -1,61 +0,0 @@
/*
* Copyright (c) 2017, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
import com.twelvemonkeys.imageio.spi.ImageWriterSpiBase;
import javax.imageio.ImageTypeSpecifier;
import java.io.IOException;
import java.util.Locale;
/**
* BMPImageWriterSpi
*/
public final class BMPImageWriterSpi extends ImageWriterSpiBase {
public BMPImageWriterSpi() {
super(new BMPProviderInfo());
}
@Override
public boolean canEncodeImage(final ImageTypeSpecifier type) {
return true;
}
@Override
public BMPImageWriter createWriterInstance(final Object extension) throws IOException {
return new BMPImageWriter(this);
}
@Override
public String getDescription(final Locale locale) {
return "Windows Device Independent Bitmap Format (BMP) Reader";
}
}
@@ -4,28 +4,26 @@
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
@@ -40,7 +38,7 @@ import javax.imageio.metadata.IIOMetadataNode;
* BMPMetadata.
*/
final class BMPMetadata extends AbstractMetadata {
/** We return metadata in the exact same form as the JRE built-in, to be compatible with the DIBImageWriter. */
/** We return metadata in the exact same form as the JRE built-in, to be compatible with the BMPImageWriter. */
public static final String nativeMetadataFormatName = "javax_imageio_bmp_1.0";
private final DIBHeader header;
@@ -170,90 +168,87 @@ final class BMPMetadata extends AbstractMetadata {
protected IIOMetadataNode getStandardCompressionNode() {
IIOMetadataNode compression = new IIOMetadataNode("Compression");
IIOMetadataNode compressionTypeName = addChildNode(compression, "CompressionTypeName", null);
// TODO: Should the compression names always match the compression names used in the ImageWriteParam?
// OR should they be as standard as possible..?
// The built-in plugin uses "BI_RGB", "BI_RLE8", "BI_RLE4", "BI_BITFIELDS", "BI_JPEG and "BI_PNG"
switch (header.compression) {
case DIB.COMPRESSION_RLE4:
case DIB.COMPRESSION_RLE8:
compressionTypeName.setAttribute("value", "RLE");
break;
case DIB.COMPRESSION_JPEG:
compressionTypeName.setAttribute("value", "JPEG");
break;
case DIB.COMPRESSION_PNG:
compressionTypeName.setAttribute("value", "PNG");
break;
case DIB.COMPRESSION_RGB:
case DIB.COMPRESSION_BITFIELDS:
case DIB.COMPRESSION_ALPHA_BITFIELDS:
default:
compressionTypeName.setAttribute("value", "NONE");
break;
}
compressionTypeName.setAttribute("value", "NONE");
return compression;
// switch (header.getImageType()) {
// case TGA.IMAGETYPE_COLORMAPPED_RLE:
// case TGA.IMAGETYPE_TRUECOLOR_RLE:
// case TGA.IMAGETYPE_MONOCHROME_RLE:
// case TGA.IMAGETYPE_COLORMAPPED_HUFFMAN:
// case TGA.IMAGETYPE_COLORMAPPED_HUFFMAN_QUADTREE:
// IIOMetadataNode node = new IIOMetadataNode("Compression");
// IIOMetadataNode compressionTypeName = new IIOMetadataNode("CompressionTypeName");
//
// // Compression can be RLE4, RLE8, PNG, JPEG or NONE
// String value = header.getImageType() == TGA.IMAGETYPE_COLORMAPPED_HUFFMAN || header.getImageType() == TGA.IMAGETYPE_COLORMAPPED_HUFFMAN_QUADTREE
// ? "Uknown" : "RLE";
// compressionTypeName.setAttribute("value", value);
// node.appendChild(compressionTypeName);
//
// IIOMetadataNode lossless = new IIOMetadataNode("Lossless");
// lossless.setAttribute("value", "TRUE"); // TODO: Unless JPEG!
// node.appendChild(lossless);
//
// return node;
// default:
// // No compression
// return null;
// }
}
@Override
protected IIOMetadataNode getStandardDataNode() {
IIOMetadataNode node = new IIOMetadataNode("Data");
// IIOMetadataNode planarConfiguration = new IIOMetadataNode("PlanarConfiguration");
// planarConfiguration.setAttribute("value", "PixelInterleaved");
// node.appendChild(planarConfiguration);
// IIOMetadataNode sampleFormat = new IIOMetadataNode("SampleFormat");
// switch (header.getImageType()) {
// case TGA.IMAGETYPE_COLORMAPPED:
// case TGA.IMAGETYPE_COLORMAPPED_RLE:
// case TGA.IMAGETYPE_COLORMAPPED_HUFFMAN:
// case TGA.IMAGETYPE_COLORMAPPED_HUFFMAN_QUADTREE:
// sampleFormat.setAttribute("value", "Index");
// break;
// default:
// sampleFormat.setAttribute("value", "UnsignedIntegral");
// break;
// }
// node.appendChild(sampleFormat);
IIOMetadataNode bitsPerSample = new IIOMetadataNode("BitsPerSample");
switch (header.getBitCount()) {
// TODO: case 0: determined by embedded format (PNG/JPEG)
case 1:
case 2:
case 4:
case 8:
bitsPerSample.setAttribute("value", createListValue(1, Integer.toString(header.getBitCount())));
break;
case 16:
// Default is 555
bitsPerSample.setAttribute("value", header.hasMasks()
? createBitsPerSampleForBitMasks()
: createListValue(3, Integer.toString(5)));
// TODO: Consult masks here!
bitsPerSample.setAttribute("value", createListValue(4, Integer.toString(4)));
break;
case 24:
bitsPerSample.setAttribute("value", createListValue(3, Integer.toString(8)));
break;
case 32:
// Default is 888
bitsPerSample.setAttribute("value", header.hasMasks()
? createBitsPerSampleForBitMasks()
: createListValue(3, Integer.toString(8)));
bitsPerSample.setAttribute("value", createListValue(4, Integer.toString(8)));
break;
}
node.appendChild(bitsPerSample);
// TODO: Do we need MSB?
// IIOMetadataNode sampleMSB = new IIOMetadataNode("SampleMSB");
// sampleMSB.setAttribute("value", createListValue(header.getChannels(), "0"));
return node;
}
private String createBitsPerSampleForBitMasks() {
boolean hasAlpha = header.masks[3] != 0;
return createListValue(hasAlpha ? 4 : 3,
Integer.toString(countMaskBits(header.masks[0])), Integer.toString(countMaskBits(header.masks[1])),
Integer.toString(countMaskBits(header.masks[2])), Integer.toString(countMaskBits(header.masks[3])));
}
private int countMaskBits(int mask) {
// See https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan
int count;
for (count = 0; mask != 0; count++) {
mask &= mask - 1; // clear the least significant bit set
}
return count;
}
private String createListValue(final int itemCount, final String... values) {
StringBuilder buffer = new StringBuilder();
@@ -270,31 +265,28 @@ final class BMPMetadata extends AbstractMetadata {
@Override
protected IIOMetadataNode getStandardDimensionNode() {
IIOMetadataNode dimension = new IIOMetadataNode("Dimension");
if (header.xPixelsPerMeter > 0 || header.yPixelsPerMeter > 0) {
IIOMetadataNode dimension = new IIOMetadataNode("Dimension");
if (header.xPixelsPerMeter > 0 && header.yPixelsPerMeter > 0) {
float ratio = header.xPixelsPerMeter / (float) header.yPixelsPerMeter;
addChildNode(dimension, "PixelAspectRatio", null)
.setAttribute("value", String.valueOf(ratio));
addChildNode(dimension, "PixelAspectRatio", null);
addChildNode(dimension, "HorizontalPhysicalPixelSpacing", null);
addChildNode(dimension, "VerticalPhysicalPixelSpacing", null);
addChildNode(dimension, "HorizontalPixelSize", null)
.setAttribute("value", String.valueOf(1f / header.xPixelsPerMeter * 1000));
addChildNode(dimension, "VerticalPixelSize", null)
.setAttribute("value", String.valueOf(1f / header.yPixelsPerMeter * 1000));
// IIOMetadataNode imageOrientation = new IIOMetadataNode("ImageOrientation");
//
// if (header.topDown) {
// imageOrientation.setAttribute("value", "FlipH");
// }
// else {
// imageOrientation.setAttribute("value", "Normal");
// }
//
// dimension.appendChild(imageOrientation);
// Hmmm.. The JRE version includes these for some reason, even if values seem to be same as default...
addChildNode(dimension, "HorizontalPhysicalPixelSpacing", null)
.setAttribute("value", String.valueOf(0));
addChildNode(dimension, "VerticalPhysicalPixelSpacing", null)
.setAttribute("value", String.valueOf(0));
return dimension;
}
if (header.topDown) {
addChildNode(dimension, "ImageOrientation", null)
.setAttribute("value", "FlipH"); // For BMP, bottom-up is "normal"...
}
return dimension;
return null;
}
// No document node
@@ -305,15 +297,16 @@ final class BMPMetadata extends AbstractMetadata {
@Override
protected IIOMetadataNode getStandardTransparencyNode() {
if (header.hasMasks() && header.masks[3] != 0) {
IIOMetadataNode transparency = new IIOMetadataNode("Transparency");
IIOMetadataNode alpha = new IIOMetadataNode("Alpha");
alpha.setAttribute("value", "nonpremultiplied");
transparency.appendChild(alpha);
return transparency;
}
return null;
// IIOMetadataNode transparency = new IIOMetadataNode("Transparency");
//
// IIOMetadataNode alpha = new IIOMetadataNode("Alpha");
//
// // TODO: Consult masks
// alpha.setAttribute("value", header.getBitCount() == 32 ? "nonpremultiplied" : "none");
// transparency.appendChild(alpha);
//
// return transparency;
}
}
@@ -1,33 +1,3 @@
/*
* Copyright (c) 2015, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
import com.twelvemonkeys.imageio.spi.ReaderWriterProviderInfo;
@@ -40,24 +10,22 @@ import com.twelvemonkeys.imageio.spi.ReaderWriterProviderInfo;
* @version $Id: BMPProviderInfo.java,v 1.0 20/03/15 harald.kuhr Exp$
*/
final class BMPProviderInfo extends ReaderWriterProviderInfo {
BMPProviderInfo() {
protected BMPProviderInfo() {
super(
BMPProviderInfo.class,
new String[] {"bmp", "BMP"},
new String[] {"bmp", "rle"},
new String[] {
"image/bmp",
"image/x-bmp",
"image/vnd.microsoft.bitmap"
"image/x-bmp"
// "image/vnd.microsoft.bitmap", // TODO: Official IANA MIME
},
"com.twelvemonkeys.imageio.plugins.bmp.BMPImageReader",
new String[] {"com.twelvemonkeys.imageio.plugins.bmp.BMPImageReaderSpi"},
"com.twelvemonkeys.imageio.plugins.bmp.BMPImageWriter",
new String[] {"com.twelvemonkeys.imageio.plugins.bmp.BMPImageWriterSpi"},
false, null, null,
null, null,
true, BMPMetadata.nativeMetadataFormatName, "com.sun.imageio.plugins.bmp.BMPMetadataFormat",
null, null
"com.sun.imageio.plugins.bmp.BMPImageWriter",
new String[]{"com.sun.imageio.plugins.bmp.BMPImageWriterSpi"}, // We support the same native metadata format
false, null, null, null, null,
true, BMPMetadata.nativeMetadataFormatName, "com.sun.imageio.plugins.bmp.BMPMetadataFormat", null, null
);
}
}
@@ -4,29 +4,28 @@
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
import com.twelvemonkeys.lang.Validate;
@@ -4,29 +4,28 @@
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
import java.awt.image.BufferedImage;
@@ -4,28 +4,26 @@
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
@@ -4,28 +4,26 @@
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
@@ -4,28 +4,26 @@
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
@@ -4,28 +4,26 @@
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
@@ -4,28 +4,26 @@
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
@@ -4,28 +4,26 @@
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
@@ -40,7 +38,7 @@ import com.twelvemonkeys.imageio.spi.ReaderWriterProviderInfo;
* @version $Id: CURProviderInfo.java,v 1.0 20/03/15 harald.kuhr Exp$
*/
final class CURProviderInfo extends ReaderWriterProviderInfo {
CURProviderInfo() {
protected CURProviderInfo() {
super(
CURProviderInfo.class,
new String[]{"cur", "CUR"},
@@ -4,28 +4,26 @@
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
@@ -339,27 +339,6 @@ abstract class DIBHeader {
}
}
void write(final DataOutput stream) throws IOException {
stream.writeInt(DIB.BITMAP_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);
// TODO: Write masks, if bitfields
}
public String getBMPVersion() {
// This is to be compatible with the native metadata of the original com.sun....BMPMetadata
return compression == DIB.COMPRESSION_BITFIELDS ? "BMP v. 3.x NT" : "BMP v. 3.x";
@@ -4,35 +4,33 @@
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
import com.twelvemonkeys.image.ImageUtil;
import com.twelvemonkeys.imageio.ImageReaderBase;
import com.twelvemonkeys.imageio.stream.SubImageInputStream;
import com.twelvemonkeys.imageio.util.IIOUtil;
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
import com.twelvemonkeys.util.WeakWeakMap;
@@ -47,6 +45,7 @@ import java.awt.event.WindowEvent;
import java.awt.image.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteOrder;
import java.util.List;
import java.util.*;
@@ -234,9 +233,8 @@ abstract class DIBImageReader extends ImageReaderBase {
ImageReader pngReader = getPNGReader();
imageInput.seek(pEntry.getOffset());
// InputStream inputStream = IIOUtil.createStreamAdapter(imageInput, pEntry.getSize());
// ImageInputStream stream = ImageIO.createImageInputStream(inputStream);
ImageInputStream stream = new SubImageInputStream(imageInput, pEntry.getSize());
InputStream inputStream = IIOUtil.createStreamAdapter(imageInput, pEntry.getSize());
ImageInputStream stream = ImageIO.createImageInputStream(inputStream);
// NOTE: Will throw IOException on later reads if input is not PNG
pngReader.setInput(stream);
@@ -286,7 +284,7 @@ abstract class DIBImageReader extends ImageReaderBase {
}
// TODO: Support this, it's already in the BMP reader, spec allows RLE4 and RLE8
if (header.getCompression() != DIB.COMPRESSION_RGB) {
if (header.getCompression() != 0) {
descriptor = new BitmapUnsupported(pEntry, String.format("Unsupported compression: %d", header.getCompression()));
}
else {
@@ -1,113 +0,0 @@
/*
* Copyright (c) 2017, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
import com.twelvemonkeys.imageio.ImageWriterBase;
import com.twelvemonkeys.imageio.plugins.bmp.DIBHeader.BitmapInfoHeader;
import javax.imageio.IIOException;
import javax.imageio.spi.ImageWriterSpi;
import java.awt.image.*;
import java.io.IOException;
import java.nio.ByteOrder;
/**
* DIBImageWriter
*/
abstract class DIBImageWriter extends ImageWriterBase {
DIBImageWriter(ImageWriterSpi provider) {
super(provider);
}
@Override
public void setOutput(Object output) {
super.setOutput(output);
imageOutput.setByteOrder(ByteOrder.LITTLE_ENDIAN);
}
void writeDIBHeader(int infoHeaderSize, int width, int height, boolean isTopDown, int pixelSize, int compression) throws IOException {
switch (infoHeaderSize) {
case DIB.BITMAP_INFO_HEADER_SIZE:
BitmapInfoHeader header = new BitmapInfoHeader();
// TODO: Consider a constructor/factory for this
header.width = width;
header.height = height;
header.topDown = isTopDown;
header.planes = 1; // Always 1 plane
header.bitCount = pixelSize;
header.compression = compression;
header.colorsUsed = 0; // Means 2 ^ bitCount
header.colorsImportant = 0; // Means all colors important
header.imageSize = header.height * ((header.width * header.bitCount + 31) / 32) * 4; // Rows padded to 32 bit
header.xPixelsPerMeter = 2835; // 72 DPI
header.yPixelsPerMeter = 2835;
header.write(imageOutput);
break;
default:
throw new IIOException("Unsupported header size: " + infoHeaderSize);
}
}
void writeUncompressed(boolean isTopDown, BufferedImage img, int height, int width) throws IOException {
// TODO: Fix
if (img.getType() != BufferedImage.TYPE_4BYTE_ABGR) {
throw new IIOException("Blows!");
}
// Support
// - TODO: IndexColorModel (ucompressed, RLE4, RLE8 or BI_PNG)
// - TODO: ComponentColorModel (1 channel gray, 3 channel BGR and 4 channel BGRA, uncompressed and RLE8? BI_BITFIELDS? BI_PNG? BI_JPEG?)
// - TODO: Packed/DirectColorModel (16 and 32 bit, BI_BITFIELDS, BI_PNG? BI_JPEG?)
Raster raster = img.getRaster();
WritableRaster rowRaster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, 1, width * 4, 4, new int[]{2, 1, 0, 3}, null);
byte[] row = ((DataBufferByte) rowRaster.getDataBuffer()).getData();
for (int i = 0; i < height; i++) {
int line = isTopDown ? i : height - 1 - i;
rowRaster.setDataElements(0, 0, raster.createChild(0, line, width, 1, 0, 0, new int[]{2, 1, 0, 3}));
imageOutput.write(row);
if (abortRequested()) {
processWriteAborted();
break;
}
processImageProgress(100f * i / (float) height);
}
}
}
@@ -4,28 +4,26 @@
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
@@ -4,38 +4,33 @@
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
import javax.imageio.IIOException;
import java.awt.*;
import java.awt.image.ColorModel;
import java.awt.image.IndexColorModel;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
@@ -47,13 +42,13 @@ import java.io.IOException;
* @see <a href="http://en.wikipedia.org/wiki/ICO_(icon_image_file_format)#Directory">Wikipedia</a>
*/
abstract class DirectoryEntry {
int width;
int height;
int colorCount;
private int width;
private int height;
private int colorCount;
int planes;
int bitCount;
int size;
int offset;
private int size;
private int offset;
DirectoryEntry() {
}
@@ -101,18 +96,6 @@ abstract class DirectoryEntry {
offset = pStream.readInt();
}
void write(final DataOutput output) throws IOException {
output.writeByte(width % 256);
output.writeByte(height % 256);
output.writeByte(colorCount);
output.writeByte(0); // Reserved
output.writeShort(1); // Color planes 0 or 1
output.writeShort(bitCount);
output.writeInt(size); // Size, depends on compression...
output.writeInt(offset);
}
public String toString() {
return String.format(
"%s: width: %d, height: %d, colors: %d, planes: %d, bit count: %d, size: %d, offset: %d",
@@ -177,16 +160,5 @@ abstract class DirectoryEntry {
* Icon directory entry.
*/
static final class ICOEntry extends DirectoryEntry {
private ICOEntry() {}
ICOEntry(final int width, final int height, final ColorModel colorModel, int size, final int offset) {
this.width = width;
this.height = height;
this.colorCount = colorModel instanceof IndexColorModel ? ((IndexColorModel) colorModel).getMapSize() : 0;
this.planes = 1;
this.bitCount = colorModel.getPixelSize();
this.size = size;
this.offset = offset;
}
}
}
@@ -4,28 +4,26 @@
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
@@ -49,4 +47,5 @@ public final class ICOImageReader extends DIBImageReader {
protected ICOImageReader(final ImageReaderSpi pProvider) {
super(pProvider);
}
}
@@ -4,28 +4,26 @@
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
@@ -1,49 +0,0 @@
/*
* Copyright (c) 2017, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
import javax.imageio.ImageWriteParam;
import java.util.Locale;
/**
* ICOImageWriteParam
*/
public final class ICOImageWriteParam extends ImageWriteParam {
public ICOImageWriteParam(final Locale locale) {
super(locale);
// The names are consistent with those from the BMPImageWriteParam
compressionTypes = new String[] {"BI_RGB", "BI_RLE8", "BI_RLE4", "BI_PNG"};
compressionType = compressionTypes[DIB.COMPRESSION_RGB];
canWriteCompressed = true;
}
}
@@ -1,327 +0,0 @@
/*
* Copyright (c) 2017, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
import com.twelvemonkeys.imageio.stream.SubImageOutputStream;
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
import javax.imageio.*;
import javax.imageio.event.IIOWriteWarningListener;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.spi.ImageWriterSpi;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import static com.twelvemonkeys.imageio.plugins.bmp.DirectoryEntry.ICOEntry;
/**
* ImageWriter implementation for Windows Icon (ICO) format.
*/
public final class ICOImageWriter extends DIBImageWriter {
// TODO: Support appending/updating an existing ICO file?
// - canInsertImage/canRemoveImage
private static final int ENTRY_SIZE = 16;
private static final int ICO_MAX_DIMENSION = 256;
private static final int INITIAL_ENTRY_COUNT = 8;
private int sequenceIndex = -1;
private ImageWriter pngDelegate;
protected ICOImageWriter(final ImageWriterSpi provider) {
super(provider);
}
@Override
protected void resetMembers() {
sequenceIndex = -1;
if (pngDelegate != null) {
pngDelegate.dispose();
pngDelegate = null;
}
}
@Override
public IIOMetadata getDefaultImageMetadata(final ImageTypeSpecifier imageType, final ImageWriteParam param) {
return null;
}
@Override
public IIOMetadata convertImageMetadata(final IIOMetadata inData, final ImageTypeSpecifier imageType, final ImageWriteParam param) {
return null;
}
@Override
public void write(final IIOMetadata streamMetadata, final IIOImage image, final ImageWriteParam param) throws IOException {
prepareWriteSequence(streamMetadata);
writeToSequence(image, param);
endWriteSequence();
}
@Override
public boolean canWriteSequence() {
return true;
}
@Override
public void prepareWriteSequence(final IIOMetadata streamMetadata) throws IOException {
assertOutput();
if (sequenceIndex >= 0) {
throw new IllegalStateException("writeSequence already started");
}
writeICOHeader();
// Count: Needs to be updated for each new image
imageOutput.writeShort(0);
sequenceIndex = 0;
// TODO: Allow passing the initial size of the directory in the stream metadata?
// - as this is much more efficient than growing...
// How do we update the "image directory" containing "image entries",
// and which must be written *before* the image data?
// - Allocate a block of N * 16 bytes
// - If image count % N > N, we need to move the first image backwards in the file and allocate another N items...
imageOutput.write(new byte[INITIAL_ENTRY_COUNT * ENTRY_SIZE]); // Allocate room for 8 entries for now
}
@Override
public void endWriteSequence() throws IOException {
assertOutput();
if (sequenceIndex < 0) {
throw new IllegalStateException("prepareWriteSequence not called");
}
sequenceIndex = -1;
}
@Override
public void writeToSequence(final IIOImage image, final ImageWriteParam param) throws IOException {
assertOutput();
if (sequenceIndex < 0) {
throw new IllegalStateException("prepareWriteSequence not called");
}
if (image.hasRaster()) {
throw new UnsupportedOperationException("image has a Raster");
}
if (sequenceIndex >= INITIAL_ENTRY_COUNT) {
growIfNecessary();
}
int width = image.getRenderedImage().getWidth();
int height = image.getRenderedImage().getHeight();
ColorModel colorModel = image.getRenderedImage().getColorModel();
// TODO: The output size may depend on the param (subsampling, source region, etc)
if (width > ICO_MAX_DIMENSION && height > ICO_MAX_DIMENSION) {
throw new IIOException(String.format("ICO maximum width or height (%d) exceeded", ICO_MAX_DIMENSION));
}
long imageOffset = imageOutput.getStreamPosition();
if (imageOffset > Integer.MAX_VALUE) {
throw new IIOException("ICO file too large");
}
// Uncompressed, RLE4/RLE8 or PNG compressed
boolean pngCompression = param != null && "BI_PNG".equals(param.getCompressionType());
processImageStarted(sequenceIndex);
if (pngCompression) {
// NOTE: Embedding a PNG in a ICO is slightly different than a BMP with BI_PNG compression,
// so we'll just handle it directly
ImageWriter writer = getPNGDelegate();
writer.setOutput(new SubImageOutputStream(imageOutput));
writer.write(null, image, copyParam(param, writer));
}
else {
RenderedImage img = image.getRenderedImage();
// ICO needs height to include height of mask, even if mask isn't written
writeDIBHeader(DIB.BITMAP_INFO_HEADER_SIZE, img.getWidth(), img.getHeight() * 2,
false, img.getColorModel().getPixelSize(), DIB.COMPRESSION_RGB);
writeUncompressed(false, (BufferedImage) img, img.getWidth(), img.getHeight());
// TODO: Write mask
imageOutput.write(new byte[((width * height + 31) / 32) * 4]);
// writeUncompressed(false, new BufferedImage(width, height, BufferedImage.TYPE_BYTE_BINARY), img.getWidth(), img.getHeight());
}
processImageComplete();
long nextPosition = imageOutput.getStreamPosition();
// Update count
imageOutput.seek(4);
imageOutput.writeShort(sequenceIndex + 1);
// Write entry
int entryPosition = 6 + sequenceIndex * ENTRY_SIZE;
imageOutput.seek(entryPosition);
long size = nextPosition - imageOffset;
writeEntry(width, height, colorModel, (int) size, (int) imageOffset);
sequenceIndex++;
imageOutput.seek(nextPosition);
}
private void writeICOHeader() throws IOException {
if (imageOutput.getStreamPosition() != 0) {
throw new IllegalStateException("Stream already written to");
}
imageOutput.writeShort(0);
imageOutput.writeShort(DIB.TYPE_ICO);
imageOutput.flushBefore(imageOutput.getStreamPosition());
}
private void growIfNecessary() {
// TODO: Allow growing the directory index...
// Move the first icon to the back, update offset
throw new IllegalStateException(String.format("Maximum number of icons supported (%d) exceeded", INITIAL_ENTRY_COUNT));
}
@Override
public ImageWriteParam getDefaultWriteParam() {
return new ICOImageWriteParam(getLocale());
}
private ImageWriteParam copyParam(final ImageWriteParam param, ImageWriter writer) {
if (param == null) {
return null;
}
ImageWriteParam writeParam = writer.getDefaultWriteParam();
writeParam.setSourceSubsampling(param.getSourceXSubsampling(), param.getSourceYSubsampling(), param.getSubsamplingXOffset(), param.getSubsamplingYOffset());
writeParam.setSourceRegion(param.getSourceRegion());
writeParam.setSourceBands(param.getSourceBands());
return writeParam;
}
private ImageWriter getPNGDelegate() {
if (pngDelegate == null) {
// There's always a PNG writer...
pngDelegate = ImageIO.getImageWritersByFormatName("PNG").next();
pngDelegate.setLocale(getLocale());
pngDelegate.addIIOWriteProgressListener(new ProgressListenerBase() {
@Override
public void imageProgress(ImageWriter source, float percentageDone) {
processImageProgress(percentageDone);
}
@Override
public void writeAborted(ImageWriter source) {
processWriteAborted();
}
});
pngDelegate.addIIOWriteWarningListener(new IIOWriteWarningListener() {
@Override
public void warningOccurred(ImageWriter source, int imageIndex, String warning) {
processWarningOccurred(sequenceIndex, warning);
}
});
}
return pngDelegate;
}
private void writeEntry(final int width, final int height, final ColorModel colorModel, int size, final int offset) throws IOException {
new ICOEntry(width, height, colorModel, size, offset)
.write(imageOutput);
}
public static void main(String[] args) throws IOException {
boolean pngCompression = false;
int firstArg = 0;
while (args.length > firstArg && args[firstArg].charAt(0) == '-') {
if (args[firstArg].equals("-p") || args[firstArg].equals("--png")) {
pngCompression = true;
}
firstArg++;
}
if (args.length - firstArg < 2) {
System.err.println("Usage: command [-p|--png] <output.ico> <input> [<input>...]");
System.exit(1);
}
try (ImageOutputStream out = ImageIO.createImageOutputStream(new File(args[firstArg++]))) {
ImageWriter writer = new ICOImageWriter(null);
writer.setOutput(out);
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionType(pngCompression ? "BI_PNG" : "BI_RGB");
writer.prepareWriteSequence(null);
for (int i = firstArg; i < args.length; i++) {
File inFile = new File(args[i]);
try (ImageInputStream input = ImageIO.createImageInputStream(inFile)) {
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
if (!readers.hasNext()) {
System.err.printf("Can't read %s\n", inFile.getAbsolutePath());
}
else {
ImageReader reader = readers.next();
reader.setInput(input);
for (int j = 0; j < reader.getNumImages(true); j++) {
IIOImage image = reader.readAll(j, null);
writer.writeToSequence(image, param);
}
}
}
}
writer.endWriteSequence();
writer.dispose();
}
}
}
@@ -1,61 +0,0 @@
/*
* Copyright (c) 2017, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
import com.twelvemonkeys.imageio.spi.ImageWriterSpiBase;
import javax.imageio.ImageTypeSpecifier;
import java.io.IOException;
import java.util.Locale;
/**
* ICOImageWriterSpi
*/
public final class ICOImageWriterSpi extends ImageWriterSpiBase {
public ICOImageWriterSpi() {
super(new ICOProviderInfo());
}
@Override
public boolean canEncodeImage(final ImageTypeSpecifier type) {
return true;
}
@Override
public ICOImageWriter createWriterInstance(final Object extension) throws IOException {
return new ICOImageWriter(this);
}
@Override
public String getDescription(final Locale locale) {
return "Windows Icon Format (ICO) Writer";
}
}
@@ -1,31 +1,29 @@
/*
* Copyright (c) 2017, Harald Kuhr
* Copyright (c) 2015, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
@@ -33,14 +31,14 @@ package com.twelvemonkeys.imageio.plugins.bmp;
import com.twelvemonkeys.imageio.spi.ReaderWriterProviderInfo;
/**
* ICOProviderInfo.
* CURProviderInfo.
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: harald.kuhr$
* @version $Id: ICOProviderInfo.java,v 1.0 20/03/15 harald.kuhr Exp$
* @version $Id: CURProviderInfo.java,v 1.0 20/03/15 harald.kuhr Exp$
*/
final class ICOProviderInfo extends ReaderWriterProviderInfo {
ICOProviderInfo() {
protected ICOProviderInfo() {
super(
ICOProviderInfo.class,
new String[]{"ico", "ICO"},
@@ -52,12 +50,9 @@ final class ICOProviderInfo extends ReaderWriterProviderInfo {
},
"com.twelvemonkeys.imageio.plugins.bmp.ICOImageReader",
new String[] {"com.twelvemonkeys.imageio.plugins.bmp.ICOImageReaderSpi"},
"com.twelvemonkeys.imageio.plugins.bmp.ICOImageWriter",
new String[] {"com.twelvemonkeys.imageio.plugins.bmp.ICOImageWriterSpi"},
false, null, null,
null, null,
true, null, null,
null, null
false, null, null, null, null,
true, null, null, null, null
);
}
}
@@ -4,34 +4,33 @@
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
import java.io.IOException;
import java.io.InputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
/**
@@ -4,34 +4,32 @@
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
import java.io.IOException;
import java.io.InputStream;
import java.io.IOException;
import java.util.Arrays;
/**
@@ -1,32 +1,3 @@
#
# Copyright (c) 2017, Harald Kuhr
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
com.twelvemonkeys.imageio.plugins.bmp.BMPImageReaderSpi
com.twelvemonkeys.imageio.plugins.bmp.CURImageReaderSpi
com.twelvemonkeys.imageio.plugins.bmp.ICOImageReaderSpi
@@ -1,31 +0,0 @@
#
# Copyright (c) 2017, Harald Kuhr
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
com.twelvemonkeys.imageio.plugins.bmp.BMPImageWriterSpi
com.twelvemonkeys.imageio.plugins.bmp.ICOImageWriterSpi
@@ -1,37 +1,6 @@
/*
* Copyright (c) 2009, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
import com.twelvemonkeys.xml.XMLSerializer;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.InOrder;
@@ -45,7 +14,6 @@ import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.spi.ImageReaderSpi;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.net.URISyntaxException;
@@ -369,20 +337,20 @@ public class BMPImageReaderTest extends ImageReaderAbstractTest<BMPImageReader>
Node expectedTree = jreMetadata.getAsTree(format);
Node actualTree = metadata.getAsTree(format);
try {
// try {
assertNodeEquals(localPath + " - " + format, expectedTree, actualTree);
}
catch (AssertionError e) {
ByteArrayOutputStream expected = new ByteArrayOutputStream();
ByteArrayOutputStream actual = new ByteArrayOutputStream();
new XMLSerializer(expected, "UTF-8").serialize(expectedTree, false);
new XMLSerializer(actual, "UTF-8").serialize(actualTree, false);
assertEquals(e.getMessage(), new String(expected.toByteArray(), "UTF-8"), new String(actual.toByteArray(), "UTF-8"));
throw e;
}
// }
// catch (AssertionError e) {
// ByteArrayOutputStream expected = new ByteArrayOutputStream();
// ByteArrayOutputStream actual = new ByteArrayOutputStream();
//
// new XMLSerializer(expected, "UTF-8").serialize(expectedTree, false);
// new XMLSerializer(actual, "UTF-8").serialize(actualTree, false);
//
// assertEquals(e.getMessage(), new String(expected.toByteArray(), "UTF-8"), new String(actual.toByteArray(), "UTF-8"));
//
// throw e;
// }
}
}
}
@@ -404,21 +372,13 @@ public class BMPImageReaderTest extends ImageReaderAbstractTest<BMPImageReader>
NodeList expectedChildNodes = expected.getChildNodes();
NodeList actualChildNodes = actual.getChildNodes();
assertTrue(message + " child length differs: " + toString(expectedChildNodes) + " != " + toString(actualChildNodes),
expectedChildNodes.getLength() <= actualChildNodes.getLength());
assertEquals(message + " child length differs: " + toString(expectedChildNodes) + " != " + toString(actualChildNodes),
expectedChildNodes.getLength(), actualChildNodes.getLength());
for (int i = 0; i < expectedChildNodes.getLength(); i++) {
Node expectedChild = expectedChildNodes.item(i);
Node actualChild = actualChildNodes.item(i);
for (int j = 0; j < actualChildNodes.getLength(); j++) {
if (actualChildNodes.item(j).getLocalName().equals(expectedChild.getLocalName())) {
actualChild = actualChildNodes.item(j);
break;
}
}
assertEquals(message + " node name differs", expectedChild.getLocalName(), actualChild.getLocalName());
assertNodeEquals(message + "/" + expectedChild.getLocalName(), expectedChild, actualChild);
}
@@ -1,33 +1,3 @@
/*
* Copyright (c) 2016, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
import com.twelvemonkeys.imageio.spi.ReaderWriterProviderInfo;
@@ -1,33 +1,3 @@
/*
* Copyright (c) 2009, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
@@ -1,33 +1,3 @@
/*
* Copyright (c) 2016, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
import com.twelvemonkeys.imageio.spi.ReaderWriterProviderInfo;
@@ -1,33 +1,3 @@
/*
* Copyright (c) 2009, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
@@ -1,33 +1,3 @@
/*
* Copyright (c) 2016, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
import com.twelvemonkeys.imageio.spi.ReaderWriterProviderInfo;
@@ -1,33 +1,3 @@
/*
* Copyright (c) 2009, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
import com.twelvemonkeys.io.enc.Decoder;
@@ -1,33 +1,3 @@
/*
* Copyright (c) 2009, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.bmp;
import com.twelvemonkeys.io.enc.Decoder;
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.5</version>
<version>3.4.4-SNAPSHOT</version>
</parent>
<artifactId>imageio-clippath</artifactId>
<name>TwelveMonkeys :: ImageIO :: Photoshop Path Support</name>
+188 -10
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Harald Kuhr
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,37 +30,215 @@
package com.twelvemonkeys.imageio.path;
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
import javax.imageio.IIOException;
import java.awt.geom.GeneralPath;
import java.awt.geom.Path2D;
import java.io.DataInput;
import java.io.EOFException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static com.twelvemonkeys.lang.Validate.isTrue;
import static com.twelvemonkeys.lang.Validate.notNull;
/**
* AdobePathBuilder.
* Creates a {@code Shape} object from an Adobe Photoshop Path resource.
*
* @deprecated Use {@link AdobePathReader} instead. This class will be removed in a future release.
* @see <a href="http://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577409_17587">Adobe Photoshop Path resource format</a>
* @author <a href="mailto:jpalmer@itemmaster.com">Jason Palmer, itemMaster LLC</a>
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
*/
public final class AdobePathBuilder {
final static boolean DEBUG = "true".equalsIgnoreCase(System.getProperty("com.twelvemonkeys.imageio.path.debug"));
private final AdobePathReader delegate;
private final DataInput data;
/**
* @see AdobePathReader#AdobePathReader(DataInput)
* Creates a path builder that will read its data from a {@code DataInput}, such as an
* {@code ImageInputStream}.
* The data length is assumed to be a multiple of 26.
*
* @param data the input to read data from.
* @throws java.lang.IllegalArgumentException if {@code data} is {@code null}
*/
public AdobePathBuilder(final DataInput data) {
this.delegate = new AdobePathReader(data);
notNull(data, "data");
this.data = data;
}
/**
* @see AdobePathReader#AdobePathReader(byte[])
* Creates a path builder that will read its data from a {@code byte} array.
* The array length must be a multiple of 26, and greater than 0.
*
* @param data the array to read data from.
* @throws java.lang.IllegalArgumentException if {@code data} is {@code null}, or not a multiple of 26.
*/
public AdobePathBuilder(final byte[] data) {
this.delegate = new AdobePathReader(data);
this(new ByteArrayImageInputStream(
notNull(data, "data"), 0,
isTrue(data.length > 0 && data.length % 26 == 0, data.length, "data.length must be a multiple of 26: %d")
));
}
/**
* @see AdobePathReader#readPath()
* Builds the path.
*
* @return the path
* @throws javax.imageio.IIOException if the input contains a bad path data.
* @throws IOException if a general I/O exception occurs during reading.
*/
public Path2D path() throws IOException {
return delegate.readPath();
List<List<AdobePathSegment>> subPaths = new ArrayList<List<AdobePathSegment>>();
List<AdobePathSegment> currentPath = null;
int currentPathLength = 0;
AdobePathSegment segment;
while ((segment = nextSegment()) != null) {
if (DEBUG) {
System.out.println(segment);
}
if (segment.selector == AdobePathSegment.OPEN_SUBPATH_LENGTH_RECORD || segment.selector == AdobePathSegment.CLOSED_SUBPATH_LENGTH_RECORD) {
if (currentPath != null) {
if (currentPathLength != currentPath.size()) {
throw new IIOException(String.format("Bad path, expected %d segments, found only %d", currentPathLength, currentPath.size()));
}
subPaths.add(currentPath);
}
currentPath = new ArrayList<AdobePathSegment>(segment.length);
currentPathLength = segment.length;
}
else if (segment.selector == AdobePathSegment.OPEN_SUBPATH_BEZIER_LINKED
|| segment.selector == AdobePathSegment.OPEN_SUBPATH_BEZIER_UNLINKED
|| segment.selector == AdobePathSegment.CLOSED_SUBPATH_BEZIER_LINKED
|| segment.selector == AdobePathSegment.CLOSED_SUBPATH_BEZIER_UNLINKED) {
if (currentPath == null) {
throw new IIOException("Bad path, missing subpath length record");
}
if (currentPath.size() >= currentPathLength) {
throw new IIOException(String.format("Bad path, expected %d segments, found%d", currentPathLength, currentPath.size()));
}
currentPath.add(segment);
}
}
// now add the last one
if (currentPath != null) {
if (currentPathLength != currentPath.size()) {
throw new IIOException(String.format("Bad path, expected %d segments, found only %d", currentPathLength, currentPath.size()));
}
subPaths.add(currentPath);
}
// now we have collected the PathPoints now create a Shape.
return pathToShape(subPaths);
}
/**
* The Correct Order... P1, P2, P3, P4, P5, P6 (Closed) moveTo(P1)
* curveTo(P1.cpl, P2.cpp, P2.ap); curveTo(P2.cpl, P3.cppy, P3.ap);
* curveTo(P3.cpl, P4.cpp, P4.ap); curveTo(P4.cpl, P5.cpp, P5.ap);
* curveTo(P5.cply, P6.cpp, P6.ap); curveTo(P6.cpl, P1.cpp, P1.ap);
* closePath()
*/
private Path2D pathToShape(final List<List<AdobePathSegment>> paths) {
GeneralPath path = new GeneralPath(Path2D.WIND_EVEN_ODD, paths.size());
GeneralPath subpath = null;
for (List<AdobePathSegment> points : paths) {
int length = points.size();
for (int i = 0; i < points.size(); i++) {
AdobePathSegment current = points.get(i);
int step = i == 0 ? 0 : i == length - 1 ? 2 : 1;
switch (step) {
// begin
case 0: {
subpath = new GeneralPath(Path2D.WIND_EVEN_ODD, length);
subpath.moveTo(current.apx, current.apy);
if (length > 1) {
AdobePathSegment next = points.get((i + 1));
subpath.curveTo(current.cplx, current.cply, next.cppx, next.cppy, next.apx, next.apy);
}
else {
subpath.lineTo(current.apx, current.apy);
}
break;
}
// middle
case 1: {
AdobePathSegment next = points.get((i + 1)); // we are always guaranteed one more.
subpath.curveTo(current.cplx, current.cply, next.cppx, next.cppy, next.apx, next.apy);
break;
}
// end
case 2: {
AdobePathSegment first = points.get(0);
if (first.selector == AdobePathSegment.CLOSED_SUBPATH_BEZIER_LINKED || first.selector == AdobePathSegment.CLOSED_SUBPATH_BEZIER_UNLINKED) {
subpath.curveTo(current.cplx, current.cply, first.cppx, first.cppy, first.apx, first.apy);
subpath.closePath();
path.append(subpath, false);
}
else {
subpath.lineTo(current.apx, current.apy);
path.append(subpath, true);
}
break;
}
}
}
}
return path;
}
private AdobePathSegment nextSegment() throws IOException {
// Each segment is 26 bytes
int selector;
try {
selector = data.readUnsignedShort();
}
catch (EOFException eof) {
// No more data, we're done
return null;
}
// Spec says Fill rule is ignored by Photoshop... Probably not.. ;-)
// TODO: Replace with switch + handle all types!
// TODO: ...or Move logic to AdobePathSegment?
if (selector == AdobePathSegment.CLOSED_SUBPATH_LENGTH_RECORD || selector == AdobePathSegment.OPEN_SUBPATH_LENGTH_RECORD) {
int size = data.readUnsignedShort();
// data.position(data.position() + 22); // Skip remaining
data.skipBytes(22);
return new AdobePathSegment(selector, size);
}
return new AdobePathSegment(
selector,
readFixedPoint(data.readInt()),
readFixedPoint(data.readInt()),
readFixedPoint(data.readInt()),
readFixedPoint(data.readInt()),
readFixedPoint(data.readInt()),
readFixedPoint(data.readInt())
);
}
private static double readFixedPoint(final int fixed) {
return ((double) fixed / 0x1000000);
}
}
@@ -1,243 +0,0 @@
/*
* Copyright (c) 2014-2020, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.path;
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
import javax.imageio.IIOException;
import java.awt.geom.Path2D;
import java.io.DataInput;
import java.io.EOFException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static com.twelvemonkeys.lang.Validate.isTrue;
import static com.twelvemonkeys.lang.Validate.notNull;
/**
* Reads a {@code Shape} object from an Adobe Photoshop Path resource.
*
* @see <a href="http://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577409_17587">Adobe Photoshop Path resource format</a>
* @author <a href="mailto:jpalmer@itemmaster.com">Jason Palmer, itemMaster LLC</a>
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
*/
public final class AdobePathReader {
static final boolean DEBUG = "true".equalsIgnoreCase(System.getProperty("com.twelvemonkeys.imageio.path.debug"));
private final DataInput data;
/**
* Creates a path reader that will read its data from a {@code DataInput},
* such as an {@code ImageInputStream}.
* The data length is assumed to be a multiple of 26.
*
* @param data the input to read data from.
* @throws java.lang.IllegalArgumentException if {@code data} is {@code null}
*/
public AdobePathReader(final DataInput data) {
notNull(data, "data");
this.data = data;
}
/**
* Creates a path reader that will read its data from a {@code byte} array.
* The array length must be a multiple of 26, and greater than 0.
*
* @param data the array to read data from.
* @throws java.lang.IllegalArgumentException if {@code data} is {@code null}, or not a multiple of 26.
*/
public AdobePathReader(final byte[] data) {
this(new ByteArrayImageInputStream(
notNull(data, "data"), 0,
isTrue(data.length > 0 && data.length % 26 == 0, data.length, "data.length must be a multiple of 26: %d")
));
}
/**
* Builds the path by reading from the supplied input.
*
* @return the path
* @throws javax.imageio.IIOException if the input contains a bad path data.
* @throws IOException if a general I/O exception occurs during reading.
*/
public Path2D readPath() throws IOException {
List<List<AdobePathSegment>> subPaths = new ArrayList<>();
List<AdobePathSegment> currentPath = null;
int currentPathLength = 0;
AdobePathSegment segment;
while ((segment = nextSegment()) != null) {
if (DEBUG) {
System.out.println(segment);
}
if (segment.selector == AdobePathSegment.OPEN_SUBPATH_LENGTH_RECORD || segment.selector == AdobePathSegment.CLOSED_SUBPATH_LENGTH_RECORD) {
if (currentPath != null) {
if (currentPathLength != currentPath.size()) {
throw new IIOException(String.format("Bad path, expected %d segments, found only %d", currentPathLength, currentPath.size()));
}
subPaths.add(currentPath);
}
currentPath = new ArrayList<>(segment.lengthOrRule);
currentPathLength = segment.lengthOrRule;
}
else if (segment.selector == AdobePathSegment.OPEN_SUBPATH_BEZIER_LINKED
|| segment.selector == AdobePathSegment.OPEN_SUBPATH_BEZIER_UNLINKED
|| segment.selector == AdobePathSegment.CLOSED_SUBPATH_BEZIER_LINKED
|| segment.selector == AdobePathSegment.CLOSED_SUBPATH_BEZIER_UNLINKED) {
if (currentPath == null) {
throw new IIOException("Bad path, missing subpath length record");
}
if (currentPath.size() >= currentPathLength) {
throw new IIOException(String.format("Bad path, expected %d segments, found%d", currentPathLength, currentPath.size()));
}
currentPath.add(segment);
}
}
// now add the last one
if (currentPath != null) {
if (currentPathLength != currentPath.size()) {
throw new IIOException(String.format("Bad path, expected %d segments, found only %d", currentPathLength, currentPath.size()));
}
subPaths.add(currentPath);
}
// We have collected the Path points, now create a Shape
return pathToShape(subPaths);
}
/**
* The Correct Order... P1, P2, P3, P4, P5, P6 (Closed) moveTo(P1)
* curveTo(P1.cpl, P2.cpp, P2.ap); curveTo(P2.cpl, P3.cpp, P3.ap);
* curveTo(P3.cpl, P4.cpp, P4.ap); curveTo(P4.cpl, P5.cpp, P5.ap);
* curveTo(P5.cpl, P6.cpp, P6.ap); curveTo(P6.cpl, P1.cpp, P1.ap);
* closePath()
*/
private Path2D pathToShape(final List<List<AdobePathSegment>> paths) {
Path2D path = new Path2D.Float(Path2D.WIND_EVEN_ODD, paths.size());
Path2D subpath = null;
for (List<AdobePathSegment> points : paths) {
int length = points.size();
for (int i = 0; i < points.size(); i++) {
AdobePathSegment current = points.get(i);
int step = i == 0 ? 0 : i == length - 1 ? 2 : 1;
switch (step) {
// Begin
case 0: {
subpath = new Path2D.Float(Path2D.WIND_EVEN_ODD, length);
subpath.moveTo(current.apx, current.apy);
if (length > 1) {
AdobePathSegment next = points.get((i + 1));
subpath.curveTo(current.cplx, current.cply, next.cppx, next.cppy, next.apx, next.apy);
}
else {
subpath.lineTo(current.apx, current.apy);
}
break;
}
// Middle
case 1: {
AdobePathSegment next = points.get((i + 1)); // We are always guaranteed one more.
subpath.curveTo(current.cplx, current.cply, next.cppx, next.cppy, next.apx, next.apy);
break;
}
// End
case 2: {
AdobePathSegment first = points.get(0);
if (first.selector == AdobePathSegment.CLOSED_SUBPATH_BEZIER_LINKED || first.selector == AdobePathSegment.CLOSED_SUBPATH_BEZIER_UNLINKED) {
subpath.curveTo(current.cplx, current.cply, first.cppx, first.cppy, first.apx, first.apy);
subpath.closePath();
path.append(subpath, false);
}
else {
subpath.lineTo(current.apx, current.apy);
path.append(subpath, true);
}
break;
}
default:
throw new AssertionError();
}
}
}
return path;
}
private AdobePathSegment nextSegment() throws IOException {
// Each segment is 26 bytes
int selector;
try {
selector = data.readUnsignedShort();
}
catch (EOFException eof) {
// No more data, we're done
return null;
}
switch (selector) {
case AdobePathSegment.INITIAL_FILL_RULE_RECORD:
case AdobePathSegment.PATH_FILL_RULE_RECORD:
// Spec says Fill rule is ignored by Photoshop, we'll read it anyway
case AdobePathSegment.CLOSED_SUBPATH_LENGTH_RECORD:
case AdobePathSegment.OPEN_SUBPATH_LENGTH_RECORD:
int lengthOrRule = data.readUnsignedShort();
data.skipBytes(22);
return new AdobePathSegment(selector, lengthOrRule);
default:
return new AdobePathSegment(
selector,
AdobePathSegment.fromFixedPoint(data.readInt()),
AdobePathSegment.fromFixedPoint(data.readInt()),
AdobePathSegment.fromFixedPoint(data.readInt()),
AdobePathSegment.fromFixedPoint(data.readInt()),
AdobePathSegment.fromFixedPoint(data.readInt()),
AdobePathSegment.fromFixedPoint(data.readInt())
);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014-2020, Harald Kuhr
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,7 +30,7 @@
package com.twelvemonkeys.imageio.path;
import static com.twelvemonkeys.lang.Validate.isTrue;
import com.twelvemonkeys.lang.Validate;
/**
* Adobe path segment.
@@ -40,17 +40,17 @@ import static com.twelvemonkeys.lang.Validate.isTrue;
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
*/
final class AdobePathSegment {
static final int CLOSED_SUBPATH_LENGTH_RECORD = 0;
static final int CLOSED_SUBPATH_BEZIER_LINKED = 1;
static final int CLOSED_SUBPATH_BEZIER_UNLINKED = 2;
static final int OPEN_SUBPATH_LENGTH_RECORD = 3;
static final int OPEN_SUBPATH_BEZIER_LINKED = 4;
static final int OPEN_SUBPATH_BEZIER_UNLINKED = 5;
static final int PATH_FILL_RULE_RECORD = 6;
static final int CLIPBOARD_RECORD = 7;
static final int INITIAL_FILL_RULE_RECORD = 8;
public final static int CLOSED_SUBPATH_LENGTH_RECORD = 0;
public final static int CLOSED_SUBPATH_BEZIER_LINKED = 1;
public final static int CLOSED_SUBPATH_BEZIER_UNLINKED = 2;
public final static int OPEN_SUBPATH_LENGTH_RECORD = 3;
public final static int OPEN_SUBPATH_BEZIER_LINKED = 4;
public final static int OPEN_SUBPATH_BEZIER_UNLINKED = 5;
public final static int PATH_FILL_RULE_RECORD = 6;
public final static int CLIPBOARD_RECORD = 7;
public final static int INITIAL_FILL_RULE_RECORD = 8;
static final String[] SELECTOR_NAMES = {
public final static String[] SELECTOR_NAMES = {
"Closed subpath length record",
"Closed subpath Bezier knot, linked",
"Closed subpath Bezier knot, unlinked",
@@ -63,18 +63,12 @@ final class AdobePathSegment {
};
final int selector;
final int lengthOrRule;
final int length;
// TODO: Consider keeping these in 8.24FP format
// Control point preceding knot
final double cppy;
final double cppx;
// Anchor point
final double apy;
final double apx;
// Control point leaving knot
final double cply;
final double cplx;
@@ -85,14 +79,11 @@ final class AdobePathSegment {
this(selector, -1, cppy, cppx, apy, apx, cply, cplx);
}
AdobePathSegment(final int selector, final int lengthOrRule) {
this(isTrue(selector == CLOSED_SUBPATH_LENGTH_RECORD || selector == OPEN_SUBPATH_LENGTH_RECORD
|| selector == PATH_FILL_RULE_RECORD || selector == INITIAL_FILL_RULE_RECORD, selector, "Expected path length or fill rule record (0/3 or 6/8): %s"),
lengthOrRule,
-1, -1, -1, -1, -1, -1);
AdobePathSegment(final int selector, final int length) {
this(selector, length, -1, -1, -1, -1, -1, -1);
}
private AdobePathSegment(final int selector, final int lengthOrRule,
private AdobePathSegment(final int selector, final int length,
final double cppy, final double cppx,
final double apy, final double apx,
final double cply, final double cplx) {
@@ -100,29 +91,27 @@ final class AdobePathSegment {
switch (selector) {
case CLOSED_SUBPATH_LENGTH_RECORD:
case OPEN_SUBPATH_LENGTH_RECORD:
isTrue(lengthOrRule >= 0, lengthOrRule, "Expected positive length: %d");
Validate.isTrue(length >= 0, length, "Bad size: %d");
break;
case CLOSED_SUBPATH_BEZIER_LINKED:
case CLOSED_SUBPATH_BEZIER_UNLINKED:
case OPEN_SUBPATH_BEZIER_LINKED:
case OPEN_SUBPATH_BEZIER_UNLINKED:
isTrue(
Validate.isTrue(
cppx >= 0 && cppx <= 1 && cppy >= 0 && cppy <= 1,
String.format("Expected point in range [0...1]: (%f, %f)", cppx ,cppy)
String.format("Unexpected point: [%f, %f]", cppx ,cppy)
);
break;
case PATH_FILL_RULE_RECORD:
case INITIAL_FILL_RULE_RECORD:
isTrue(lengthOrRule == 0 || lengthOrRule == 1, lengthOrRule, "Expected rule (1 or 0): %d");
break;
case CLIPBOARD_RECORD:
case INITIAL_FILL_RULE_RECORD:
break;
default:
throw new IllegalArgumentException("Unknown selector: " + selector);
throw new IllegalArgumentException("Bad selector: " + selector);
}
this.selector = selector;
this.lengthOrRule = lengthOrRule;
this.length = length;
this.cppy = cppy;
this.cppx = cppx;
this.apy = apy;
@@ -131,14 +120,6 @@ final class AdobePathSegment {
this.cplx = cplx;
}
static int toFixedPoint(final double value) {
return (int) Math.round(value * 0x1000000);
}
static double fromFixedPoint(final int fixed) {
return ((double) fixed / 0x1000000);
}
@Override
public boolean equals(final Object other) {
if (this == other) {
@@ -158,7 +139,7 @@ final class AdobePathSegment {
&& Double.compare(that.cppx, cppx) == 0
&& Double.compare(that.cppy, cppy) == 0
&& selector == that.selector
&& lengthOrRule == that.lengthOrRule;
&& length == that.length;
}
@@ -167,7 +148,7 @@ final class AdobePathSegment {
long tempBits;
int result = selector;
result = 31 * result + lengthOrRule;
result = 31 * result + length;
tempBits = Double.doubleToLongBits(cppy);
result = 31 * result + (int) (tempBits ^ (tempBits >>> 32));
tempBits = Double.doubleToLongBits(cppx);
@@ -189,13 +170,13 @@ final class AdobePathSegment {
switch (selector) {
case INITIAL_FILL_RULE_RECORD:
case PATH_FILL_RULE_RECORD:
return String.format("Rule(selector=%s, rule=%d)", SELECTOR_NAMES[selector], lengthOrRule);
return String.format("Rule(selector=%s, rule=%d)", SELECTOR_NAMES[selector], length);
case CLOSED_SUBPATH_LENGTH_RECORD:
case OPEN_SUBPATH_LENGTH_RECORD:
return String.format("Len(selector=%s, length=%d)", SELECTOR_NAMES[selector], lengthOrRule);
return String.format("Len(selector=%s, totalPoints=%d)", SELECTOR_NAMES[selector], length);
default:
// fall-through
}
return String.format("Pt(pre=(%.3f, %.3f), knot=(%.3f, %.3f), post=(%.3f, %.3f), selector=%s)", cppx, cppy, apx, apy, cplx, cply, SELECTOR_NAMES[selector]);
return String.format("Pt(preX=%.3f, preY=%.3f, knotX=%.3f, knotY=%.3f, postX=%.3f, postY=%.3f, selector=%s)", cppx, cppy, apx, apy, cplx, cply, SELECTOR_NAMES[selector]);
}
}
@@ -1,278 +0,0 @@
/*
* Copyright (c) 2020 Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.path;
import com.twelvemonkeys.imageio.metadata.psd.PSD;
import java.awt.*;
import java.awt.geom.Path2D;
import java.awt.geom.PathIterator;
import java.io.ByteArrayOutputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static com.twelvemonkeys.imageio.path.AdobePathReader.DEBUG;
import static com.twelvemonkeys.imageio.path.AdobePathSegment.*;
import static com.twelvemonkeys.lang.Validate.isTrue;
import static com.twelvemonkeys.lang.Validate.notNull;
/**
* Writes a {@code Shape} object to an Adobe Photoshop Path or Path resource.
*
* @see <a href="http://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577409_17587">Adobe Photoshop Path resource format</a>
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
*/
public final class AdobePathWriter {
// TODO: Might need to get hold of more real Photoshop samples to tune this threshold...
private static final double COLLINEARITY_THRESHOLD = 0.00000001;
private final List<AdobePathSegment> segments;
/**
* Creates an AdobePathWriter for the given path.
* <p>
* NOTE: Photoshop paths are stored with the coordinates
* (0,0) representing the top left corner of the image,
* and (1,1) representing the bottom right corner,
* regardless of image dimensions.
* </p>
*
* @param path A {@code Shape} instance that has {@link Path2D#WIND_EVEN_ODD WIND_EVEN_ODD} rule,
* is contained within the rectangle [x=0.0,y=0.0,w=1.0,h=1.0], and is closed.
* @throws IllegalArgumentException if {@code path} is {@code null},
* the paths winding rule is not @link Path2D#WIND_EVEN_ODD} or
* the paths bounding box is outside [x=0.0,y=0.0,w=1.0,h=1.0] or
* the path is not closed.
*/
public AdobePathWriter(final Shape path) {
notNull(path, "path");
isTrue(new Rectangle(0, 0, 1, 1).contains(path.getBounds2D()), path.getBounds2D(), "Path bounds must be within [x=0,y=0,w=1,h=1]: %s");
segments = pathToSegments(path.getPathIterator(null));
}
// TODO: Look at the API so that conversion both ways are aligned. The read part builds a path from List<List<AdobePathSegment>...
private static List<AdobePathSegment> pathToSegments(final PathIterator pathIterator) {
// TODO: Test if PS really ignores winding rule as documented... Otherwise we could support writing non-zero too.
isTrue(pathIterator.getWindingRule() == Path2D.WIND_EVEN_ODD, pathIterator.getWindingRule(), "Only even/odd winding rule supported: %d");
double[] coords = new double[6];
AdobePathSegment prev = new AdobePathSegment(CLOSED_SUBPATH_BEZIER_LINKED, 0, 0, 0, 0, 0, 0);
List<AdobePathSegment> subpath = new ArrayList<>();
List<AdobePathSegment> segments = new ArrayList<>();
segments.add(new AdobePathSegment(PATH_FILL_RULE_RECORD, 0));
segments.add(new AdobePathSegment(INITIAL_FILL_RULE_RECORD, 0));
while (!pathIterator.isDone()) {
int segmentType = pathIterator.currentSegment(coords);
if (DEBUG) {
System.out.println("segmentType: " + segmentType);
System.out.println("coords: " + Arrays.toString(coords));
}
// We write collinear points as linked segments
boolean collinear = isCollinear(prev.cppx, prev.cppy, prev.apx, prev.apy, coords[0], coords[1]);
switch (segmentType) {
case PathIterator.SEG_MOVETO:
// TODO: What if we didn't close before the moveto? Start new segment here?
// Dummy starting point, will be updated later
prev = new AdobePathSegment(CLOSED_SUBPATH_BEZIER_LINKED, 0, 0, coords[1], coords[0], 0, 0);
break;
case PathIterator.SEG_LINETO:
subpath.add(new AdobePathSegment(collinear ? CLOSED_SUBPATH_BEZIER_LINKED : CLOSED_SUBPATH_BEZIER_UNLINKED, prev.cppy, prev.cppx, prev.apy, prev.apx, coords[1], coords[0]));
prev = new AdobePathSegment(CLOSED_SUBPATH_BEZIER_LINKED, coords[1], coords[0], coords[1], coords[0], 0, 0);
break;
case PathIterator.SEG_QUADTO:
subpath.add(new AdobePathSegment(collinear ? CLOSED_SUBPATH_BEZIER_LINKED : CLOSED_SUBPATH_BEZIER_UNLINKED, prev.cppy, prev.cppx, prev.apy, prev.apx, coords[1], coords[0]));
prev = new AdobePathSegment(CLOSED_SUBPATH_BEZIER_LINKED, coords[3], coords[2], coords[3], coords[2], 0, 0);
break;
case PathIterator.SEG_CUBICTO:
subpath.add(new AdobePathSegment(collinear ? CLOSED_SUBPATH_BEZIER_LINKED : CLOSED_SUBPATH_BEZIER_UNLINKED, prev.cppy, prev.cppx, prev.apy, prev.apx, coords[1], coords[0]));
prev = new AdobePathSegment(CLOSED_SUBPATH_BEZIER_LINKED, coords[3], coords[2], coords[5], coords[4], 0, 0);
break;
case PathIterator.SEG_CLOSE:
AdobePathSegment initial = subpath.get(0);
if (initial.apx != prev.apx || initial.apy != prev.apy) {
// Line back to initial if last anchor point does not equal initial anchor
collinear = isCollinear(prev.cppx, prev.cppy, initial.apx, initial.apy, initial.apx, initial.apy);
subpath.add(new AdobePathSegment(collinear ? CLOSED_SUBPATH_BEZIER_LINKED : CLOSED_SUBPATH_BEZIER_UNLINKED, prev.cppy, prev.cppx, prev.apy, prev.apx, initial.apy, initial.apx));
prev = new AdobePathSegment(CLOSED_SUBPATH_BEZIER_LINKED, initial.apy, initial.apx, initial.apy, initial.apx, 0, 0);
}
close(initial, prev, subpath, segments);
subpath.clear();
break;
}
pathIterator.next();
}
// If subpath is not empty at this point, there was no close segment...
// Wrap up if coordinates match, otherwise throw exception
if (!subpath.isEmpty()) {
AdobePathSegment initial = subpath.get(0);
if (initial.apx != prev.apx || initial.apy != prev.apy) {
throw new IllegalArgumentException("Path must be closed");
}
close(initial, prev, subpath, segments);
}
return segments;
}
private static void close(AdobePathSegment initial, AdobePathSegment prev, List<AdobePathSegment> subpath, List<AdobePathSegment> segments) {
// Replace initial point.
boolean collinear = isCollinear(prev.cppx, prev.cppy, initial.apx, initial.apy, initial.cplx, initial.cply);
subpath.set(0, new AdobePathSegment(collinear ? CLOSED_SUBPATH_BEZIER_LINKED : CLOSED_SUBPATH_BEZIER_UNLINKED, prev.cppy, prev.cppx, initial.apy, initial.apx, initial.cply, initial.cplx));
// Add to full path
segments.add(new AdobePathSegment(CLOSED_SUBPATH_LENGTH_RECORD, subpath.size()));
segments.addAll(subpath);
}
private static boolean isCollinear(double x1, double y1, double x2, double y2, double x3, double y3) {
// Photoshop seems to write as linked if all points are the same....
return (x1 == x2 && x2 == x3 && y1 == y2 && y2 == y3) ||
(x1 != x2 || y1 != y2) && (x2 != x3 || y2 != y3) &&
Math.abs(x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)) <= COLLINEARITY_THRESHOLD; // With some slack...
}
/**
* Writes the path as a complete Adobe Photoshop clipping path resource to the given stream.
*
* @param resourceId the resource id, typically {@link PSD#RES_CLIPPING_PATH} (0x07D0).
* @param output the stream to write to.
* @throws IOException if an I/O exception happens during writing.
*/
public void writePathResource(int resourceId, final DataOutput output) throws IOException {
output.writeInt(PSD.RESOURCE_TYPE);
output.writeShort(resourceId);
output.writeShort(0); // Path name (Pascal string) empty + pad
output.writeInt(segments.size() * 26); // Resource size
writePath(output);
}
/**
* Writes the path as a set of Adobe Photoshop path segments to the given stream.
*
* @param output the stream to write to.
* @throws IOException if an I/O exception happens during writing.
*/
public void writePath(final DataOutput output) throws IOException {
if (DEBUG) {
System.out.println("segments: " + segments.size());
System.out.println(segments);
}
for (AdobePathSegment segment : segments) {
switch (segment.selector) {
case PATH_FILL_RULE_RECORD:
case INITIAL_FILL_RULE_RECORD:
// The first 26-byte path record contains a selector value of 6, path fill rule record.
// The remaining 24 bytes of the first record are zeroes. Paths use even/odd ruling.
output.writeShort(segment.selector);
output.write(new byte[24]);
break;
case OPEN_SUBPATH_LENGTH_RECORD:
case CLOSED_SUBPATH_LENGTH_RECORD:
output.writeShort(segment.selector);
output.writeShort(segment.lengthOrRule); // Subpath length
output.write(new byte[22]);
break;
default:
output.writeShort(segment.selector);
output.writeInt(toFixedPoint(segment.cppy));
output.writeInt(toFixedPoint(segment.cppx));
output.writeInt(toFixedPoint(segment.apy));
output.writeInt(toFixedPoint(segment.apx));
output.writeInt(toFixedPoint(segment.cply));
output.writeInt(toFixedPoint(segment.cplx));
break;
}
}
}
/**
* Transforms the path to a byte array, containing a complete Adobe Photoshop path resource.
*
* @param resourceId the resource id, typically {@link PSD#RES_CLIPPING_PATH} (0x07D0).
* @return a new byte array, containing the clipping path resource.
*/
public byte[] writePathResource(int resourceId) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
try (DataOutputStream stream = new DataOutputStream(bytes)) {
writePathResource(resourceId, stream);
}
catch (IOException e) {
throw new AssertionError("ByteArrayOutputStream threw IOException", e);
}
return bytes.toByteArray();
}
/**
* Transforms the path to a byte array, containing a set of Adobe Photoshop path segments.
*
* @return a new byte array, containing the path segments.
*/
public byte[] writePath() {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
try (DataOutputStream stream = new DataOutputStream(bytes)) {
writePath(stream);
}
catch (IOException e) {
throw new AssertionError("ByteArrayOutputStream threw IOException", e);
}
return bytes.toByteArray();
}
}
+19 -164
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2014-2020, Harald Kuhr
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -43,29 +43,22 @@ import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader;
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
import com.twelvemonkeys.imageio.stream.SubImageInputStream;
import javax.imageio.*;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;
import javax.imageio.stream.MemoryCacheImageInputStream;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import static com.twelvemonkeys.lang.Validate.isTrue;
import static com.twelvemonkeys.lang.Validate.notNull;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
/**
* Support for various Adobe Photoshop Path related operations:
@@ -73,11 +66,10 @@ import static java.util.Collections.singletonMap;
* <li>Extract a path from an image input stream, {@link #readPath}</li>
* <li>Apply a given path to a given {@code BufferedImage} {@link #applyClippingPath}</li>
* <li>Read an image with path applied {@link #readClipped}</li>
* <li>Write an image with embedded path {@link #writeClipped}</li>
* </ul>
*
* @see <a href="http://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577409_17587">Adobe Photoshop Path resource format</a>
* @see AdobePathReader
* @see com.twelvemonkeys.imageio.path.AdobePathBuilder
* @author <a href="mailto:jpalmer@itemmaster.com">Jason Palmer, itemMaster LLC</a>
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: harald.kuhr$
@@ -98,7 +90,7 @@ public final class Paths {
* @throws javax.imageio.IIOException if the input contains a bad path data.
* @throws java.lang.IllegalArgumentException is {@code stream} is {@code null}.
*
* @see AdobePathReader
* @see com.twelvemonkeys.imageio.path.AdobePathBuilder
*/
public static Path2D readPath(final ImageInputStream stream) throws IOException {
notNull(stream, "stream");
@@ -107,7 +99,7 @@ public final class Paths {
if (magic == PSD.RESOURCE_TYPE) {
// This is a PSD Image Resource Block, we can parse directly
return readPathFromPhotoshopResources(stream);
return buildPathFromPhotoshopResources(stream);
}
else if (magic == PSD.SIGNATURE_8BPS) {
// PSD version
@@ -123,15 +115,17 @@ public final class Paths {
long imageResourcesLen = stream.readUnsignedInt();
// Image resources
return readPathFromPhotoshopResources(new SubImageInputStream(stream, imageResourcesLen));
return buildPathFromPhotoshopResources(new SubImageInputStream(stream, imageResourcesLen));
}
else if (magic >>> 16 == JPEG.SOI && (magic & 0xff00) == 0xff00) {
// JPEG version
Map<Integer, List<String>> segmentIdentifiers = singletonMap(JPEG.APP13, singletonList("Photoshop 3.0"));
Map<Integer, java.util.List<String>> segmentIdentifiers = new LinkedHashMap<>();
segmentIdentifiers.put(JPEG.APP13, singletonList("Photoshop 3.0"));
List<JPEGSegment> photoshop = JPEGSegmentUtil.readSegments(stream, segmentIdentifiers);
if (!photoshop.isEmpty()) {
return readPathFromPhotoshopResources(new MemoryCacheImageInputStream(photoshop.get(0).data()));
return buildPathFromPhotoshopResources(new MemoryCacheImageInputStream(photoshop.get(0).data()));
}
}
else if (magic >>> 16 == TIFF.BYTE_ORDER_MARK_BIG_ENDIAN && (magic & 0xffff) == TIFF.TIFF_MAGIC
@@ -143,7 +137,7 @@ public final class Paths {
Entry photoshop = directory.getEntryById(TIFF.TAG_PHOTOSHOP);
if (photoshop != null) {
return readPathFromPhotoshopResources(new ByteArrayImageInputStream((byte[]) photoshop.getValue()));
return buildPathFromPhotoshopResources(new ByteArrayImageInputStream((byte[]) photoshop.getValue()));
}
}
@@ -162,17 +156,17 @@ public final class Paths {
}
}
private static Path2D readPathFromPhotoshopResources(final ImageInputStream stream) throws IOException {
private static Path2D buildPathFromPhotoshopResources(final ImageInputStream stream) throws IOException {
Directory resourceBlocks = new PSDReader().read(stream);
if (AdobePathReader.DEBUG) {
if (AdobePathBuilder.DEBUG) {
System.out.println("resourceBlocks: " + resourceBlocks);
}
Entry pathResource = resourceBlocks.getEntryById(PSD.RES_CLIPPING_PATH);
Entry resourceBlock = resourceBlocks.getEntryById(PSD.RES_CLIPPING_PATH);
if (pathResource != null) {
return new AdobePathReader((byte[]) pathResource.getValue()).readPath();
if (resourceBlock != null) {
return new AdobePathBuilder((byte[]) resourceBlock.getValue()).path();
}
return null;
@@ -260,149 +254,9 @@ public final class Paths {
return applyClippingPath(clip, image);
}
/**
* Writes the image along with a clipping path resource, in the given format, to the supplied output.
* The image is written to the
* {@code ImageOutputStream} starting at the current stream
* pointer, overwriting existing stream data from that point
* forward, if present.
* <p>
* Note: As {@link ImageIO#write(RenderedImage, String, ImageOutputStream)}, this method does
* <em>not</em> close the output stream.
* It is the responsibility of the caller to close the stream, if desired.
* </p>
* <p>
* Implementation note: Only JPEG (using the "javax_imageio_jpeg_image_1.0" metadata format) and
* TIFF (using the "javax_imageio_tiff_image_1.0" or "com_sun_media_imageio_plugins_tiff_image_1.0" metadata formats)
* formats are currently supported.
* </p>
*
* @param image the image to be written, may not be {@code null}.
* @param clipPath the clip path, may not be {@code null}.
* @param formatName the informal format name, may not be {@code null}.
* @param output the stream to write to, may not be {@code null}.
*
* @return {@code true} if the image was written,
* otherwise {@code false} (ie. no writer was found for the specified format).
*
* @exception IllegalArgumentException if any parameter is {@code null}.
* @exception IOException if an error occurs during writing.
*/
public static boolean writeClipped(final RenderedImage image, Shape clipPath, final String formatName, final ImageOutputStream output) throws IOException {
if (image == null) {
throw new IllegalArgumentException("image == null!");
}
if (formatName == null) {
throw new IllegalArgumentException("formatName == null!");
}
if (output == null) {
throw new IllegalArgumentException("output == null!");
}
ImageTypeSpecifier type = ImageTypeSpecifier.createFromRenderedImage(image);
Iterator<ImageWriter> writers = ImageIO.getImageWriters(type, formatName);
if (writers.hasNext()) {
ImageWriter writer = writers.next();
ImageWriteParam param = writer.getDefaultWriteParam();
IIOMetadata metadata = writer.getDefaultImageMetadata(type, param);
List<String> metadataFormats = asList(metadata.getMetadataFormatNames());
byte[] pathResource = new AdobePathWriter(clipPath).writePathResource(PSD.RES_CLIPPING_PATH);
if (metadataFormats.contains("javax_imageio_tiff_image_1.0") || metadataFormats.contains("com_sun_media_imageio_plugins_tiff_image_1.0")) {
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionType("Deflate");
// Check if the format is that of the bundled TIFF writer, otherwise use JAI format
String metadataFormat = metadataFormats.contains("javax_imageio_tiff_image_1.0")
? "javax_imageio_tiff_image_1.0"
: "com_sun_media_imageio_plugins_tiff_image_1.0"; // Fails in mergeTree, if not supported
IIOMetadataNode root = new IIOMetadataNode(metadataFormat);
IIOMetadataNode ifd = new IIOMetadataNode("TIFFIFD");
IIOMetadataNode pathField = new IIOMetadataNode("TIFFField");
pathField.setAttribute("number", String.valueOf(TIFF.TAG_PHOTOSHOP));
IIOMetadataNode pathValue = new IIOMetadataNode("TIFFUndefined"); // Use undefined for simplicity, could also use bytes
pathValue.setAttribute("value", arrayAsString(pathResource));
pathField.appendChild(pathValue);
ifd.appendChild(pathField);
root.appendChild(ifd);
metadata.mergeTree(metadataFormat, root);
writer.setOutput(output);
writer.write(null, new IIOImage(image, null, metadata), param);
return true;
}
else if (metadataFormats.contains("javax_imageio_jpeg_image_1.0")) {
String metadataFormat = "javax_imageio_jpeg_image_1.0";
IIOMetadataNode root = new IIOMetadataNode(metadataFormat);
root.appendChild(new IIOMetadataNode("JPEGvariety"));
IIOMetadataNode sequence = new IIOMetadataNode("markerSequence");
// App13/Photshop 3.0
IIOMetadataNode unknown = new IIOMetadataNode("unknown");
unknown.setAttribute("MarkerTag", Integer.toString(JPEG.APP13 & 0xFF));
byte[] identfier = "Photoshop 3.0".getBytes(StandardCharsets.US_ASCII);
byte[] data = new byte[identfier.length + 1 + pathResource.length];
System.arraycopy(identfier, 0, data, 0, identfier.length);
System.arraycopy(pathResource, 0, data, identfier.length + 1, pathResource.length);
unknown.setUserObject(data);
sequence.appendChild(unknown);
root.appendChild(sequence);
metadata.mergeTree(metadataFormat, root);
writer.setOutput(output);
writer.write(null, new IIOImage(image, null, metadata), param);
return true;
}
// TODO: Else if PSD... Requires PSD write + new metadata format...
}
return false;
}
private static String arrayAsString(byte[] bytes) {
if (bytes == null || bytes.length == 0) {
return "";
}
StringBuilder builder = new StringBuilder();
for (int i = 0; ; i++) {
builder.append(bytes[i]);
if (i == bytes.length - 1) {
return builder.toString();
}
builder.append(","); // NOTE: The javax_imageio_tiff_image_1.0 format does not allow whitespace here...
}
}
// Test code
public static void main(final String[] args) throws IOException, InterruptedException {
BufferedImage destination;
if (args.length == 1) {
// Embedded path
destination = readClipped(ImageIO.createImageInputStream(new File(args[0])));
}
else {
// Separate path and image
try (ImageInputStream input = ImageIO.createImageInputStream(new File(args[1]))) {
destination = applyClippingPath(readPath(input), ImageIO.read(new File(args[0])));
}
}
BufferedImage destination = readClipped(ImageIO.createImageInputStream(new File(args[0])));
File tempFile = File.createTempFile("clipped-", ".png");
tempFile.deleteOnExit();
@@ -416,4 +270,5 @@ public final class Paths {
System.err.printf("%s not deleted\n", tempFile);
}
}
}
@@ -43,7 +43,6 @@ import static com.twelvemonkeys.imageio.path.PathsTest.assertPathEquals;
import static com.twelvemonkeys.imageio.path.PathsTest.readExpectedPath;
import static org.junit.Assert.assertNotNull;
@SuppressWarnings("deprecation")
public class AdobePathBuilderTest {
@Test(expected = IllegalArgumentException.class)
@@ -1,165 +0,0 @@
/*
* Copyright (c) 2020 Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.path;
import org.junit.Test;
import javax.imageio.IIOException;
import javax.imageio.stream.ImageInputStream;
import java.awt.geom.Path2D;
import java.io.DataInput;
import java.io.IOException;
import java.nio.ByteBuffer;
import static com.twelvemonkeys.imageio.path.PathsTest.assertPathEquals;
import static com.twelvemonkeys.imageio.path.PathsTest.readExpectedPath;
import static org.junit.Assert.assertNotNull;
public class AdobePathReaderTest {
@Test(expected = IllegalArgumentException.class)
public void testCreateNullBytes() {
new AdobePathReader((byte[]) null);
}
@Test(expected = IllegalArgumentException.class)
public void testCreateNull() {
new AdobePathReader((DataInput) null);
}
@Test(expected = IllegalArgumentException.class)
public void testCreateEmpty() {
new AdobePathReader(new byte[0]);
}
@Test(expected = IllegalArgumentException.class)
public void testCreateShortPath() {
new AdobePathReader(new byte[3]);
}
@Test(expected = IllegalArgumentException.class)
public void testCreateImpossiblePath() {
new AdobePathReader(new byte[7]);
}
@Test
public void testCreate() {
new AdobePathReader(new byte[52]);
}
@Test
public void testNoPath() throws IOException {
Path2D path = new AdobePathReader(new byte[26]).readPath();
assertNotNull(path);
}
@Test(expected = IIOException.class)
public void testShortPath() throws IOException {
byte[] data = new byte[26];
ByteBuffer buffer = ByteBuffer.wrap(data);
buffer.putShort((short) AdobePathSegment.CLOSED_SUBPATH_LENGTH_RECORD);
buffer.putShort((short) 1);
Path2D path = new AdobePathReader(data).readPath();
assertNotNull(path);
}
@Test(expected = IIOException.class)
public void testShortPathToo() throws IOException {
byte[] data = new byte[52];
ByteBuffer buffer = ByteBuffer.wrap(data);
buffer.putShort((short) AdobePathSegment.CLOSED_SUBPATH_LENGTH_RECORD);
buffer.putShort((short) 2);
buffer.position(buffer.position() + 22);
buffer.putShort((short) AdobePathSegment.CLOSED_SUBPATH_BEZIER_LINKED);
Path2D path = new AdobePathReader(data).readPath();
assertNotNull(path);
}
@Test(expected = IIOException.class)
public void testLongPath() throws IOException {
byte[] data = new byte[78];
ByteBuffer buffer = ByteBuffer.wrap(data);
buffer.putShort((short) AdobePathSegment.CLOSED_SUBPATH_LENGTH_RECORD);
buffer.putShort((short) 1);
buffer.position(buffer.position() + 22);
buffer.putShort((short) AdobePathSegment.CLOSED_SUBPATH_BEZIER_LINKED);
buffer.position(buffer.position() + 24);
buffer.putShort((short) AdobePathSegment.CLOSED_SUBPATH_BEZIER_LINKED);
Path2D path = new AdobePathReader(data).readPath();
assertNotNull(path);
}
@Test(expected = IIOException.class)
public void testPathMissingLength() throws IOException {
byte[] data = new byte[26];
ByteBuffer buffer = ByteBuffer.wrap(data);
buffer.putShort((short) AdobePathSegment.CLOSED_SUBPATH_BEZIER_LINKED);
Path2D path = new AdobePathReader(data).readPath();
assertNotNull(path);
}
@Test
public void testSimplePath() throws IOException {
// We'll read this from a real file, with hardcoded offsets for simplicity
// PSD IRB: offset: 34, length: 32598
// Clipping path: offset: 31146, length: 1248
ImageInputStream stream = PathsTest.resourceAsIIOStream("/psd/grape_with_path.psd");
stream.seek(34 + 31146);
byte[] data = new byte[1248];
stream.readFully(data);
Path2D path = new AdobePathReader(data).readPath();
assertNotNull(path);
assertPathEquals(path, readExpectedPath("/ser/grape-path.ser"));
}
@Test
public void testComplexPath() throws IOException {
// We'll read this from a real file, with hardcoded offsets for simplicity
// PSD IRB: offset: 16970, length: 11152
// Clipping path: offset: 9250, length: 1534
ImageInputStream stream = PathsTest.resourceAsIIOStream("/tiff/big-endian-multiple-clips.tif");
stream.seek(16970 + 9250);
byte[] data = new byte[1534];
stream.readFully(data);
Path2D path = new AdobePathReader(data).readPath();
assertNotNull(path);
assertPathEquals(path, readExpectedPath("/ser/multiple-clips.ser"));
}
}
@@ -63,7 +63,7 @@ public class AdobePathSegmentTest {
AdobePathSegment segment = new AdobePathSegment(AdobePathSegment.OPEN_SUBPATH_LENGTH_RECORD, 42);
assertEquals(AdobePathSegment.OPEN_SUBPATH_LENGTH_RECORD, segment.selector);
assertEquals(42, segment.lengthOrRule);
assertEquals(42, segment.length);
assertEquals(-1, segment.cppx, 0);
assertEquals(-1, segment.cppy, 0);
assertEquals(-1, segment.apx, 0);
@@ -82,7 +82,7 @@ public class AdobePathSegmentTest {
AdobePathSegment segment = new AdobePathSegment(AdobePathSegment.CLOSED_SUBPATH_LENGTH_RECORD, 27);
assertEquals(AdobePathSegment.CLOSED_SUBPATH_LENGTH_RECORD, segment.selector);
assertEquals(27, segment.lengthOrRule);
assertEquals(27, segment.length);
assertEquals(-1, segment.cppx, 0);
assertEquals(-1, segment.cppy, 0);
assertEquals(-1, segment.apx, 0);
@@ -98,7 +98,7 @@ public class AdobePathSegmentTest {
AdobePathSegment segment = new AdobePathSegment(AdobePathSegment.OPEN_SUBPATH_BEZIER_LINKED, .5, .5, 0, 0, 1, 1);
assertEquals(AdobePathSegment.OPEN_SUBPATH_BEZIER_LINKED, segment.selector);
assertEquals(-1, segment.lengthOrRule);
assertEquals(-1, segment.length);
assertEquals(.5, segment.cppx, 0);
assertEquals(.5, segment.cppy, 0);
assertEquals(0, segment.apx, 0);
@@ -122,7 +122,7 @@ public class AdobePathSegmentTest {
AdobePathSegment segment = new AdobePathSegment(AdobePathSegment.OPEN_SUBPATH_BEZIER_UNLINKED, .5, .5, 0, 0, 1, 1);
assertEquals(AdobePathSegment.OPEN_SUBPATH_BEZIER_UNLINKED, segment.selector);
assertEquals(-1, segment.lengthOrRule);
assertEquals(-1, segment.length);
assertEquals(.5, segment.cppx, 0);
assertEquals(.5, segment.cppy, 0);
assertEquals(0, segment.apx, 0);
@@ -149,7 +149,7 @@ public class AdobePathSegmentTest {
AdobePathSegment segment = new AdobePathSegment(AdobePathSegment.CLOSED_SUBPATH_BEZIER_LINKED, .5, .5, 0, 0, 1, 1);
assertEquals(AdobePathSegment.CLOSED_SUBPATH_BEZIER_LINKED, segment.selector);
assertEquals(-1, segment.lengthOrRule);
assertEquals(-1, segment.length);
assertEquals(.5, segment.cppx, 0);
assertEquals(.5, segment.cppy, 0);
assertEquals(0, segment.apx, 0);
@@ -173,7 +173,7 @@ public class AdobePathSegmentTest {
AdobePathSegment segment = new AdobePathSegment(AdobePathSegment.CLOSED_SUBPATH_BEZIER_UNLINKED, .5, .5, 0, 0, 1, 1);
assertEquals(AdobePathSegment.CLOSED_SUBPATH_BEZIER_UNLINKED, segment.selector);
assertEquals(-1, segment.lengthOrRule);
assertEquals(-1, segment.length);
assertEquals(.5, segment.cppx, 0);
assertEquals(.5, segment.cppy, 0);
assertEquals(0, segment.apx, 0);
@@ -195,11 +195,11 @@ public class AdobePathSegmentTest {
@Test
public void testToStringRule() {
String string = new AdobePathSegment(AdobePathSegment.INITIAL_FILL_RULE_RECORD, 0).toString();
String string = new AdobePathSegment(AdobePathSegment.INITIAL_FILL_RULE_RECORD, 2).toString();
assertTrue(string, string.startsWith("Rule"));
assertTrue(string, string.contains("Initial"));
assertTrue(string, string.contains("fill"));
assertTrue(string, string.contains("rule=0"));
assertTrue(string, string.contains("rule=2"));
}
@Test
@@ -208,13 +208,13 @@ public class AdobePathSegmentTest {
assertTrue(string, string.startsWith("Len"));
assertTrue(string, string.contains("Closed"));
assertTrue(string, string.contains("subpath"));
assertTrue(string, string.contains("length=2"));
assertTrue(string, string.contains("totalPoints=2"));
string = new AdobePathSegment(AdobePathSegment.OPEN_SUBPATH_LENGTH_RECORD, 42).toString();
assertTrue(string, string.startsWith("Len"));
assertTrue(string, string.contains("Open"));
assertTrue(string, string.contains("subpath"));
assertTrue(string, string.contains("length=42"));
assertTrue(string, string.contains("totalPoints=42"));
}
@Test
@@ -1,416 +0,0 @@
/*
* Copyright (c) 2020 Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.path;
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
import org.junit.Test;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.geom.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import static com.twelvemonkeys.imageio.path.AdobePathSegment.*;
import static com.twelvemonkeys.imageio.path.PathsTest.assertPathEquals;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
/**
* AdobePathWriterTest.
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by haraldk: harald.kuhr$
* @version : AdobePathWriterTest.java,v 1.0 2020-01-02 harald.kuhr Exp$
*/
public class AdobePathWriterTest {
@Test(expected = IllegalArgumentException.class)
public void testCreateWriterNull() {
new AdobePathWriter(null);
}
@Test(expected = IllegalArgumentException.class)
public void testCreateWriterInvalid() {
new AdobePathWriter(new Path2D.Double(Path2D.WIND_NON_ZERO));
}
@Test(expected = IllegalArgumentException.class)
public void testCreateWriterOutOfBounds() {
Path2D path = new Path2D.Float(Path2D.WIND_EVEN_ODD);
path.append(new Ellipse2D.Double(.5, 0.5, 2, 2), false);
new AdobePathWriter(path);
}
@Test
public void testCreateWriterValid() {
Path2D path = new Path2D.Float(Path2D.WIND_EVEN_ODD);
path.append(new Ellipse2D.Double(.25, .25, .5, .5), false);
new AdobePathWriter(path);
}
@Test
public void testCreateWriterMulti() {
Path2D path = new GeneralPath(Path2D.WIND_EVEN_ODD);
path.append(new Ellipse2D.Float(.25f, .25f, .5f, .5f), false);
path.append(new Rectangle2D.Double(0, 0, 1, .5), false);
path.append(new Polygon(new int[] {1, 2, 0, 1}, new int[] {0, 2, 2, 0}, 4)
.getPathIterator(AffineTransform.getScaleInstance(1 / 2.0, 1 / 2.0)), false);
new AdobePathWriter(path);
}
@Test(expected = IllegalArgumentException.class)
public void testCreateNotClosed() {
GeneralPath path = new GeneralPath(Path2D.WIND_EVEN_ODD);
path.moveTo(.5, .5);
path.lineTo(1, .5);
path.curveTo(1, 1, 1, 1, .5, 1);
new AdobePathWriter(path).writePath();
}
@Test
public void testCreateClosed() {
GeneralPath path = new GeneralPath(Path2D.WIND_EVEN_ODD);
path.moveTo(.5, .5);
path.lineTo(1, .5);
path.curveTo(1, 1, 1, 1, .5, 1);
path.closePath();
byte[] bytes = new AdobePathWriter(path).writePath();
assertEquals(6 * 26, bytes.length);
int off = 0;
// Path/initial fill rule: Even-Odd (0)
assertArrayEquals(new byte[] {0, PATH_FILL_RULE_RECORD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, INITIAL_FILL_RULE_RECORD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
// Rectangle 1: 0, 0, 1, .5
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_LENGTH_RECORD, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_UNLINKED, 0, -128, 0, 0, 0, -128, 0, 0, 0, -128, 0, 0, 0, -128, 0, 0, 0, -128, 0, 0, 1, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_UNLINKED, 0, -128, 0, 0, 1, 0, 0, 0, 0, -128, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_UNLINKED, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, -128, 0, 0, 0, -128, 0, 0, 0, -128, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
// Sanity
assertEquals(bytes.length, off);
}
@Test
public void testCreateImplicitClosed() {
GeneralPath path = new GeneralPath(Path2D.WIND_EVEN_ODD);
path.moveTo(.5, .5);
path.lineTo(1, .5);
path.curveTo(1, 1, 1, 1, .5, 1);
path.lineTo(.5, .5);
byte[] bytes = new AdobePathWriter(path).writePath();
assertEquals(6 * 26, bytes.length);
int off = 0;
// Path/initial fill rule: Even-Odd (0)
assertArrayEquals(new byte[] {0, PATH_FILL_RULE_RECORD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, INITIAL_FILL_RULE_RECORD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
// Rectangle 1: 0, 0, 1, .5
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_LENGTH_RECORD, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_UNLINKED, 0, -128, 0, 0, 0, -128, 0, 0, 0, -128, 0, 0, 0, -128, 0, 0, 0, -128, 0, 0, 1, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_UNLINKED, 0, -128, 0, 0, 1, 0, 0, 0, 0, -128, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_UNLINKED, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, -128, 0, 0, 0, -128, 0, 0, 0, -128, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
// Sanity
assertEquals(bytes.length, off);
}
@Test
public void testCreateDoubleClosed() {
GeneralPath path = new GeneralPath(Path2D.WIND_EVEN_ODD);
path.moveTo(.5, .5);
path.lineTo(1, .5);
path.curveTo(1, 1, 1, 1, .5, 1);
path.lineTo(.5, .5);
path.closePath();
byte[] bytes = new AdobePathWriter(path).writePath();
assertEquals(6 * 26, bytes.length);
int off = 0;
// Path/initial fill rule: Even-Odd (0)
assertArrayEquals(new byte[] {0, PATH_FILL_RULE_RECORD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, INITIAL_FILL_RULE_RECORD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
// Rectangle 1: 0, 0, 1, .5
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_LENGTH_RECORD, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_UNLINKED, 0, -128, 0, 0, 0, -128, 0, 0, 0, -128, 0, 0, 0, -128, 0, 0, 0, -128, 0, 0, 1, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_UNLINKED, 0, -128, 0, 0, 1, 0, 0, 0, 0, -128, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_UNLINKED, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, -128, 0, 0, 0, -128, 0, 0, 0, -128, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
// Sanity
assertEquals(bytes.length, off);
}
@Test
public void testWriteToStream() throws IOException {
Path2D path = new GeneralPath(Path2D.WIND_EVEN_ODD);
path.append(new Ellipse2D.Double(0, 0, 1, 1), false);
path.append(new Ellipse2D.Double(.5, .5, .5, .5), false);
path.append(new Ellipse2D.Double(.25, .25, .5, .5), false);
AdobePathWriter pathCreator = new AdobePathWriter(path);
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
try (ImageOutputStream output = ImageIO.createImageOutputStream(byteStream)) {
pathCreator.writePath(output);
}
assertEquals(17 * 26, byteStream.size());
byte[] bytes = byteStream.toByteArray();
int off = 0;
// Path/initial fill rule: Even-Odd (0)
assertArrayEquals(new byte[] {0, PATH_FILL_RULE_RECORD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, INITIAL_FILL_RULE_RECORD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
// Elipse 1: 0, 0, 1, 1
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_LENGTH_RECORD, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_LINKED, 0, 57, 78, -68, 1, 0, 0, 0, 0, -128, 0, 0, 1, 0, 0, 0, 0, -58, -79, 68, 1, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_LINKED, 1, 0, 0, 0, 0, -58, -79, 68, 1, 0, 0, 0, 0, -128, 0, 0, 1, 0, 0, 0, 0, 57, 78, -68},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_LINKED, 0, -58, -79, 68, 0, 0, 0, 0, 0, -128, 0, 0, 0, 0, 0, 0, 0, 57, 78, -68, 0, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_LINKED, 0, 0, 0, 0, 0, 57, 78, -68, 0, 0, 0, 0, 0, -128, 0, 0, 0, 0, 0, 0, 0, -58, -79, 68},
Arrays.copyOfRange(bytes, off, off += 26));
// Elipse 2: .5, .5, .5, .5
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_LENGTH_RECORD, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_LINKED, 0, -100, -89, 94, 1, 0, 0, 0, 0, -64, 0, 0, 1, 0, 0, 0, 0, -29, 88, -94, 1, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_LINKED, 1, 0, 0, 0, 0, -29, 88, -94, 1, 0, 0, 0, 0, -64, 0, 0, 1, 0, 0, 0, 0, -100, -89, 94},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_LINKED, 0, -29, 88, -94, 0, -128, 0, 0, 0, -64, 0, 0, 0, -128, 0, 0, 0, -100, -89, 94, 0, -128, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_LINKED, 0, -128, 0, 0, 0, -100, -89, 94, 0, -128, 0, 0, 0, -64, 0, 0, 0, -128, 0, 0, 0, -29, 88, -94},
Arrays.copyOfRange(bytes, off, off += 26));
// Elipse32: .25, .25, .5, .5
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_LENGTH_RECORD, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_LINKED, 0, 92, -89, 94, 0, -64, 0, 0, 0, -128, 0, 0, 0, -64, 0, 0, 0, -93, 88, -94, 0, -64, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_LINKED, 0, -64, 0, 0, 0, -93, 88, -94, 0, -64, 0, 0, 0, -128, 0, 0, 0, -64, 0, 0, 0, 92, -89, 94},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_LINKED, 0, -93, 88, -94, 0, 64, 0, 0, 0, -128, 0, 0, 0, 64, 0, 0, 0, 92, -89, 94, 0, 64, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_LINKED, 0, 64, 0, 0, 0, 92, -89, 94, 0, 64, 0, 0, 0, -128, 0, 0, 0, 64, 0, 0, 0, -93, 88, -94},
Arrays.copyOfRange(bytes, off, off += 26));
// Sanity
assertEquals(bytes.length, off);
}
@Test
public void testCreateArray() {
Path2D path = new GeneralPath(Path2D.WIND_EVEN_ODD);
path.append(new Rectangle2D.Double(0, 0, 1, .5), false);
path.append(new Rectangle2D.Double(.25, .25, .5, .5), false);
AdobePathWriter pathCreator = new AdobePathWriter(path);
byte[] bytes = pathCreator.writePath();
assertEquals(12 * 26, bytes.length);
int off = 0;
// Path/initial fill rule: Even-Odd (0)
assertArrayEquals(new byte[] {0, PATH_FILL_RULE_RECORD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, INITIAL_FILL_RULE_RECORD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
// Rectangle 1: 0, 0, 1, .5
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_LENGTH_RECORD, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_UNLINKED, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_UNLINKED, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, -128, 0, 0, 1, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_UNLINKED, 0, -128, 0, 0, 1, 0, 0, 0, 0, -128, 0, 0, 1, 0, 0, 0, 0, -128, 0, 0, 0, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_UNLINKED, 0, -128, 0, 0, 0, 0, 0, 0, 0, -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
// Rectangle 2: .25, .25, .5, .5
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_LENGTH_RECORD, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_UNLINKED, 0, 64, 0, 0, 0, 64, 0, 0, 0, 64, 0, 0, 0, 64, 0, 0, 0, 64, 0, 0, 0, -64, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_UNLINKED, 0, 64, 0, 0, 0, -64, 0, 0, 0, 64, 0, 0, 0, -64, 0, 0, 0, -64, 0, 0, 0, -64, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_UNLINKED, 0, -64, 0, 0, 0, -64, 0, 0, 0, -64, 0, 0, 0, -64, 0, 0, 0, -64, 0, 0, 0, 64, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
assertArrayEquals(new byte[] {0, CLOSED_SUBPATH_BEZIER_UNLINKED, 0, -64, 0, 0, 0, 64, 0, 0, 0, -64, 0, 0, 0, 64, 0, 0, 0, 64, 0, 0, 0, 64, 0, 0},
Arrays.copyOfRange(bytes, off, off += 26));
// Sanity
assertEquals(bytes.length, off);
}
@Test
public void testRoundtrip0() throws IOException {
Path2D path = new GeneralPath(Path2D.WIND_EVEN_ODD);
path.append(new Rectangle2D.Double(0, 0, 1, .5), false);
path.append(new Rectangle2D.Double(.25, .25, .5, .5), false);
byte[] bytes = new AdobePathWriter(path).writePath();
Path2D readPath = new AdobePathReader(new ByteArrayImageInputStream(bytes)).readPath();
assertEquals(path.getWindingRule(), readPath.getWindingRule());
assertEquals(path.getBounds2D(), readPath.getBounds2D());
// TODO: Would be nice, but hard to do, as we convert all points to cubic...
// assertPathEquals(path, readPath);
}
@Test
public void testRoundtrip1() throws IOException {
// We'll read this from a real file, with hardcoded offsets for simplicity
// PSD IRB: offset: 34, length: 32598
// Clipping path: offset: 31146, length: 1248
ImageInputStream stream = PathsTest.resourceAsIIOStream("/psd/grape_with_path.psd");
stream.seek(34 + 31146);
byte[] data = new byte[1248];
stream.readFully(data);
Path2D path = new AdobePathReader(data).readPath();
byte[] bytes = new AdobePathWriter(path).writePath();
Path2D readPath = new AdobePathReader(new ByteArrayImageInputStream(bytes)).readPath();
assertEquals(path.getWindingRule(), readPath.getWindingRule());
assertEquals(path.getBounds2D(), readPath.getBounds2D());
assertPathEquals(path, readPath);
assertEquals(data.length, bytes.length);
// Path segment 3 contains some unknown bits in the filler bytes, we'll ignore those...
cleanLengthRecords(data);
assertEquals(formatSegments(data), formatSegments(bytes));
assertArrayEquals(data, bytes);
}
private static void cleanLengthRecords(byte[] data) {
for (int i = 0; i < data.length; i += 26) {
if (data[i + 1] == CLOSED_SUBPATH_LENGTH_RECORD) {
// Clean everything after record type and length field
for (int j = 4; j < 26; j++) {
data[i + j] = 0;
}
}
}
}
private static String formatSegments(byte[] data) {
StringBuilder builder = new StringBuilder(data.length * 5);
for (int i = 0; i < data.length; i += 26) {
builder.append(Arrays.toString(Arrays.copyOfRange(data, i, i + 26))).append('\n');
}
return builder.toString();
}
@Test
public void testRoundtrip2() throws IOException {
// We'll read this from a real file, with hardcoded offsets for simplicity
// PSD IRB: offset: 16970, length: 11152
// Clipping path: offset: 9250, length: 1534
ImageInputStream stream = PathsTest.resourceAsIIOStream("/tiff/big-endian-multiple-clips.tif");
stream.seek(16970 + 9250);
byte[] data = new byte[1534];
stream.readFully(data);
Path2D path = new AdobePathReader(data).readPath();
byte[] bytes = new AdobePathWriter(path).writePath();
Path2D readPath = new AdobePathReader(new ByteArrayImageInputStream(bytes)).readPath();
assertEquals(path.getWindingRule(), readPath.getWindingRule());
assertEquals(path.getBounds2D(), readPath.getBounds2D());
assertPathEquals(path, readPath);
assertEquals(data.length, bytes.length);
// Path segment 3 and 48 contains some unknown bits in the filler bytes, we'll ignore that:
cleanLengthRecords(data);
assertEquals(formatSegments(data), formatSegments(bytes));
assertArrayEquals(data, bytes);
}
}
@@ -38,18 +38,15 @@ import org.junit.Test;
import javax.imageio.ImageIO;
import javax.imageio.spi.IIORegistry;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.geom.GeneralPath;
import java.awt.geom.Path2D;
import java.awt.geom.PathIterator;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import static org.junit.Assert.*;
import static org.junit.Assume.assumeTrue;
/**
* PathsTest.
@@ -128,12 +125,12 @@ public class PathsTest {
}
@Test(expected = IllegalArgumentException.class)
public void testApplyClippingPathNullPath() {
public void testApplyClippingPathNullPath() throws IOException {
Paths.applyClippingPath(null, new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_GRAY));
}
@Test(expected = IllegalArgumentException.class)
public void testApplyClippingPathNullSource() {
public void testApplyClippingPathNullSource() throws IOException {
Paths.applyClippingPath(new GeneralPath(), null);
}
@@ -150,7 +147,7 @@ public class PathsTest {
assertEquals(source.getWidth(), image.getWidth());
assertEquals(source.getHeight(), image.getHeight());
// Transparent
assertEquals(Transparency.TRANSLUCENT, image.getColorModel().getTransparency());
assertTrue(image.getColorModel().getTransparency() == Transparency.TRANSLUCENT);
// Corners (at least) should be transparent
assertEquals(0, image.getRGB(0, 0));
@@ -164,9 +161,8 @@ public class PathsTest {
// TODO: Mor sophisticated test that tests all pixels outside path...
}
@SuppressWarnings("ConstantConditions")
@Test(expected = IllegalArgumentException.class)
public void testApplyClippingPathNullDestination() {
public void testApplyClippingPathNullDestination() throws IOException {
Paths.applyClippingPath(new GeneralPath(), new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_GRAY), null);
}
@@ -213,7 +209,7 @@ public class PathsTest {
assertEquals(857, image.getWidth());
assertEquals(1800, image.getHeight());
// Transparent
assertEquals(Transparency.TRANSLUCENT, image.getColorModel().getTransparency());
assertTrue(image.getColorModel().getTransparency() == Transparency.TRANSLUCENT);
// Corners (at least) should be transparent
assertEquals(0, image.getRGB(0, 0));
@@ -234,70 +230,34 @@ public class PathsTest {
}
static Path2D readExpectedPath(final String resource) throws IOException {
try (ObjectInputStream ois = new ObjectInputStream(PathsTest.class.getResourceAsStream(resource))) {
ObjectInputStream ois = new ObjectInputStream(PathsTest.class.getResourceAsStream(resource));
try {
return (Path2D) ois.readObject();
}
catch (ClassNotFoundException e) {
throw new IOException(e);
}
finally {
ois.close();
}
}
static void assertPathEquals(final Path2D expectedPath, final Path2D actualPath) {
assertNotNull("Expected path is null, check your tests...", expectedPath);
assertNotNull(actualPath);
PathIterator expectedIterator = expectedPath.getPathIterator(null);
PathIterator actualIterator = actualPath.getPathIterator(null);
float[] expectedCoords = new float[6];
float[] actualCoords = new float[6];
while(!expectedIterator.isDone()) {
assertFalse("Less points than expected", actualIterator.isDone());
while(!actualIterator.isDone()) {
int expectedType = expectedIterator.currentSegment(expectedCoords);
int actualType = actualIterator.currentSegment(actualCoords);
assertEquals("Unexpected segment type", expectedType, actualType);
assertArrayEquals("Unexpected coordinates", expectedCoords, actualCoords, 0);
assertEquals(expectedType, actualType);
assertArrayEquals(expectedCoords, actualCoords, 0);
actualIterator.next();
expectedIterator.next();
}
assertTrue("More points than expected", actualIterator.isDone());
}
@Test
public void testWriteJPEG() throws IOException {
Path2D originalPath = readExpectedPath("/ser/multiple-clips.ser");
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
BufferedImage image = new BufferedImage(2, 2, BufferedImage.TYPE_3BYTE_BGR);
try (ImageOutputStream stream = ImageIO.createImageOutputStream(bytes)) {
boolean written = Paths.writeClipped(image, originalPath, "JPEG", stream);
assertTrue(written);
}
assertTrue(bytes.size() > 1024); // Actual size may be plugin specific...
Path2D actualPath = Paths.readPath(new ByteArrayImageInputStream(bytes.toByteArray()));
assertPathEquals(originalPath, actualPath);
}
@Test
public void testWriteTIFF() throws IOException {
Path2D originalPath = readExpectedPath("/ser/grape-path.ser");
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
BufferedImage image = new BufferedImage(2, 2, BufferedImage.TYPE_INT_ARGB);
try (ImageOutputStream stream = ImageIO.createImageOutputStream(bytes)) {
boolean written = Paths.writeClipped(image, originalPath, "TIFF", stream);
assumeTrue(written); // TIFF support is optional
}
assertTrue(bytes.size() > 1024); // Actual size may be plugin specific...
Path2D actualPath = Paths.readPath(new ByteArrayImageInputStream(bytes.toByteArray()));
assertPathEquals(originalPath, actualPath);
}
}
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.5</version>
<version>3.4.4-SNAPSHOT</version>
</parent>
<artifactId>imageio-core</artifactId>
<name>TwelveMonkeys :: ImageIO :: Core</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.5</version>
<version>3.4.4-SNAPSHOT</version>
</parent>
<artifactId>imageio-hdr</artifactId>
<name>TwelveMonkeys :: ImageIO :: HDR plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.5</version>
<version>3.4.4-SNAPSHOT</version>
</parent>
<artifactId>imageio-icns</artifactId>
<name>TwelveMonkeys :: ImageIO :: ICNS plugin</name>
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Harald Kuhr
* Copyright (c) 2011, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -92,28 +92,14 @@ interface ICNS {
/** 128Ă—128 8-bit mask. */
int t8mk = ('t' << 24) + ('8' << 16) + ('m' << 8) + 'k';
/** 16x16 JPEG2000 or PNG icon (10.7+). */
int icp4 = ('i' << 24) + ('c' << 16) + ('p' << 8) + '4';
/** 32x32 JPEG2000 or PNG icon (10.7+). */
int icp5 = ('i' << 24) + ('c' << 16) + ('p' << 8) + '5';
/** 64x64 JPEG2000 or PNG icon (10.7+). */
int icp6 = ('i' << 24) + ('c' << 16) + ('p' << 8) + '6';
/** 128x128 JPEG2000 or PNG icon (10.7+). */
int ic07 = ('i' << 24) + ('c' << 16) + ('0' << 8) + '7';
/** 256Ă—256 JPEG 2000 or PNG icon (10.5+). */
/** 256Ă—256 JPEG 2000 or PNG icon (10.x+). */
int ic08 = ('i' << 24) + ('c' << 16) + ('0' << 8) + '8';
/** 512Ă—512 JPEG 2000 or PNG icon (10.5+). */
/** 512Ă—512 JPEG 2000 or PNG icon (10.x+). */
int ic09 = ('i' << 24) + ('c' << 16) + ('0' << 8) + '9';
/** 1024Ă—1024 JPEG2000 or PNG icon (10.7+) OR 512x512@2x "retina" (10.8+). */
/** 1024Ă—1024 PNG icon (10.7+). */
int ic10 = ('i' << 24) + ('c' << 16) + ('1' << 8) + '0';
/** 16x16@2x "retina" JPEG2000 or PNG icon (10.8+). */
int ic11 = ('i' << 24) + ('c' << 16) + ('1' << 8) + '1';
/** 32x32@2x "retina" JPEG2000 or PNG icon (10.8+). */
int ic12 = ('i' << 24) + ('c' << 16) + ('1' << 8) + '2';
/** 128x128@2x "retina" JPEG2000 or PNG icon (10.8+). */
int ic13 = ('i' << 24) + ('c' << 16) + ('1' << 8) + '3';
/** 256x256@2x "retina" JPEG2000 or PNG icon (10.8+). */
int ic14 = ('i' << 24) + ('c' << 16) + ('1' << 8) + '4';
/** Unknown (Version). */
int icnV = ('i' << 24) + ('c' << 16) + ('n' << 8) + 'V';
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Harald Kuhr
* Copyright (c) 2011, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,7 +31,6 @@
package com.twelvemonkeys.imageio.plugins.icns;
import com.twelvemonkeys.imageio.ImageReaderBase;
import com.twelvemonkeys.imageio.stream.SubImageInputStream;
import com.twelvemonkeys.imageio.util.IIOUtil;
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
@@ -423,7 +422,7 @@ public final class ICNSImageReader extends ImageReaderBase {
private BufferedImage readForeignFormat(int imageIndex, final ImageReadParam param, final IconResource resource) throws IOException {
// TODO: Optimize by caching readers that work?
ImageInputStream stream = new SubImageInputStream(imageInput, resource.length);
ImageInputStream stream = ImageIO.createImageInputStream(IIOUtil.createStreamAdapter(imageInput, resource.length));
try {
// Try first using ImageIO
@@ -442,7 +441,7 @@ public final class ICNSImageReader extends ImageReaderBase {
}
else {
stream.close();
stream = new SubImageInputStream(imageInput, resource.length);
stream = ImageIO.createImageInputStream(IIOUtil.createStreamAdapter(imageInput, resource.length));
}
}
finally {
@@ -525,28 +524,10 @@ public final class ICNSImageReader extends ImageReaderBase {
}
IconResource resource = IconResource.read(imageInput);
if (resource.isTOC()) {
// TODO: IconResource.readTOC()?
int resourceCount = (resource.length - ICNS.RESOURCE_HEADER_SIZE) / ICNS.RESOURCE_HEADER_SIZE;
long pos = resource.start + resource.length;
for (int i = 0; i < resourceCount; i++) {
resource = IconResource.read(pos, imageInput);
pos += resource.length;
addResource(resource);
}
}
else {
addResource(resource);
}
// System.err.println("resource: " + resource);
lastResourceRead = resource;
return resource;
}
private void addResource(final IconResource resource) {
// Filter out special cases like 'icnV' or 'TOC ' resources
if (resource.isMaskType()) {
masks.add(resource);
@@ -554,6 +535,8 @@ public final class ICNSImageReader extends ImageReaderBase {
else if (!resource.isUnknownType()) {
icons.add(resource);
}
return resource;
}
private void readeFileHeader() throws IOException {
@@ -1,273 +0,0 @@
/*
* Copyright (c) 2017, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.icns;
import com.twelvemonkeys.imageio.ImageWriterBase;
import com.twelvemonkeys.imageio.stream.SubImageOutputStream;
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
import javax.imageio.*;
import javax.imageio.event.IIOWriteWarningListener;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.spi.ImageWriterSpi;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
/**
* ICNSImageWriter
*/
public final class ICNSImageWriter extends ImageWriterBase {
private int sequenceIndex = -1;
private ImageWriter pngDelegate;
ICNSImageWriter(ImageWriterSpi provider) {
super(provider);
}
@Override
protected void resetMembers() {
sequenceIndex = -1;
if (pngDelegate != null) {
pngDelegate.dispose();
pngDelegate = null;
}
}
@Override
public IIOMetadata getDefaultImageMetadata(final ImageTypeSpecifier imageType, final ImageWriteParam param) {
return null;
}
@Override
public IIOMetadata convertImageMetadata(final IIOMetadata inData, final ImageTypeSpecifier imageType, final ImageWriteParam param) {
return null;
}
@Override
public void write(final IIOMetadata streamMetadata, final IIOImage image, final ImageWriteParam param) throws IOException {
prepareWriteSequence(streamMetadata);
writeToSequence(image, param);
endWriteSequence();
}
@Override
public boolean canWriteSequence() {
return true;
}
@Override
public void prepareWriteSequence(final IIOMetadata streamMetadata) throws IOException {
assertOutput();
// TODO: Allow TOC resource to be passed as stream metadata?
// - We only need number of icons to be written later
// - The contents of the TOC could be updated while adding to the sequence
if (sequenceIndex >= 0) {
throw new IllegalStateException("writeSequence already started");
}
writeICNSHeader();
sequenceIndex = 0;
}
@Override
public void endWriteSequence() throws IOException {
assertOutput();
if (sequenceIndex < 0) {
throw new IllegalStateException("prepareWriteSequence not called");
}
// TODO: Now that we know the number of icon resources, we could move all data backwards
// and write a TOC... But I don't think the benefit will outweigh the cost.
sequenceIndex = -1;
}
@Override
public void writeToSequence(final IIOImage image, final ImageWriteParam param) throws IOException {
assertOutput();
if (sequenceIndex < 0) {
throw new IllegalStateException("prepareWriteSequence not called");
}
if (image.hasRaster()) {
throw new UnsupportedOperationException("image has a Raster");
}
long resourceStart = imageOutput.getStreamPosition();
// TODO: Allow for other formats based on param?
// - Uncompressed/RLE (only allowed up to 128x128)?
// - JPEG2000 not very likely...
// Validate icon size, get icon resource type based on size and compression
// TODO: Allow smaller, centered in larger square? Resize?
imageOutput.writeInt(IconResource.typeFromImage(image.getRenderedImage(), "PNG"));
imageOutput.writeInt(0); // Size, update later
processImageStarted(sequenceIndex);
// Write icon in PNG format
ImageWriter writer = getPNGDelegate();
writer.setOutput(new SubImageOutputStream(imageOutput));
writer.write(null, image, copyParam(param, writer));
processImageComplete();
long resourceEnd = imageOutput.getStreamPosition();
if (resourceEnd > Integer.MAX_VALUE) {
throw new IIOException("File too large for ICNS");
}
int length = (int) (resourceEnd - resourceStart);
// Update file length field
imageOutput.seek(4);
imageOutput.writeInt((int) resourceEnd);
// Update resource length field
imageOutput.seek(resourceStart + 4);
imageOutput.writeInt((length));
// Prepare for next iteration
imageOutput.seek(resourceEnd);
}
private ImageWriteParam copyParam(final ImageWriteParam param, ImageWriter writer) {
if (param == null) {
return null;
}
ImageWriteParam writeParam = writer.getDefaultWriteParam();
writeParam.setSourceSubsampling(param.getSourceXSubsampling(), param.getSourceYSubsampling(), param.getSubsamplingXOffset(), param.getSubsamplingYOffset());
writeParam.setSourceRegion(param.getSourceRegion());
writeParam.setSourceBands(param.getSourceBands());
return writeParam;
}
private ImageWriter getPNGDelegate() {
if (pngDelegate == null) {
// There's always a PNG writer...
pngDelegate = ImageIO.getImageWritersByFormatName("PNG").next();
pngDelegate.setLocale(getLocale());
pngDelegate.addIIOWriteProgressListener(new ProgressListenerBase() {
@Override
public void imageProgress(ImageWriter source, float percentageDone) {
processImageProgress(percentageDone);
}
@Override
public void writeAborted(ImageWriter source) {
processWriteAborted();
}
});
pngDelegate.addIIOWriteWarningListener(new IIOWriteWarningListener() {
@Override
public void warningOccurred(ImageWriter source, int imageIndex, String warning) {
processWarningOccurred(sequenceIndex, warning);
}
});
}
return pngDelegate;
}
private void writeICNSHeader() throws IOException {
if (imageOutput.getStreamPosition() != 0) {
throw new IllegalStateException("Stream already written to");
}
imageOutput.writeInt(ICNS.MAGIC);
imageOutput.writeInt(8); // Length of file, in bytes, must be updated while writing
}
public static void main(String[] args) throws IOException {
boolean pngCompression = false;
int firstArg = 0;
while (args.length > firstArg && args[firstArg].charAt(0) == '-') {
if (args[firstArg].equals("-p") || args[firstArg].equals("--png")) {
pngCompression = true;
}
firstArg++;
}
if (args.length - firstArg < 2) {
System.err.println("Usage: command [-p|--png] <output.ico> <input> [<input>...]");
System.exit(1);
}
try (ImageOutputStream out = ImageIO.createImageOutputStream(new File(args[firstArg++]))) {
ImageWriter writer = new ICNSImageWriter(null);
writer.setOutput(out);
ImageWriteParam param = writer.getDefaultWriteParam();
// For now, we only support PNG...
// param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
// param.setCompressionType(pngCompression ? "BI_PNG" : "BI_RGB");
writer.prepareWriteSequence(null);
for (int i = firstArg; i < args.length; i++) {
File inFile = new File(args[i]);
try (ImageInputStream input = ImageIO.createImageInputStream(inFile)) {
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);
if (!readers.hasNext()) {
System.err.printf("Can't read %s\n", inFile.getAbsolutePath());
}
else {
ImageReader reader = readers.next();
reader.setInput(input);
for (int j = 0; j < reader.getNumImages(true); j++) {
IIOImage image = reader.readAll(j, null);
writer.writeToSequence(image, param);
}
}
}
}
writer.endWriteSequence();
writer.dispose();
}
}
}
@@ -1,60 +0,0 @@
/*
* Copyright (c) 2017, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.icns;
import com.twelvemonkeys.imageio.spi.ImageWriterSpiBase;
import javax.imageio.ImageTypeSpecifier;
import java.util.Locale;
/**
* ICNSImageWriterSpi
*/
public final class ICNSImageWriterSpi extends ImageWriterSpiBase {
public ICNSImageWriterSpi() {
super(new ICNSProviderInfo());
}
@Override
public boolean canEncodeImage(final ImageTypeSpecifier type) {
return true;
}
@Override
public ICNSImageWriter createWriterInstance(final Object extension) {
return new ICNSImageWriter(this);
}
@Override
public String getDescription(final Locale locale) {
return "Apple Icon Image (icns) format Writer";
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Harald Kuhr
* Copyright (c) 2015, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -40,7 +40,7 @@ import com.twelvemonkeys.imageio.spi.ReaderWriterProviderInfo;
* @version $Id: ICNSProviderInfo.java,v 1.0 20/03/15 harald.kuhr Exp$
*/
final class ICNSProviderInfo extends ReaderWriterProviderInfo {
ICNSProviderInfo() {
protected ICNSProviderInfo() {
super(
ICNSProviderInfo.class,
new String[]{"icns", "ICNS"},
@@ -50,12 +50,9 @@ final class ICNSProviderInfo extends ReaderWriterProviderInfo {
},
"com.twelvemonkeys.imageio.plugins.icns.ICNSImageReader",
new String[] {"com.twelvemonkeys.imageio.plugins.icns.ICNSImageReaderSpi"},
"com.twelvemonkeys.imageio.plugins.icns.ICNSImageWriter",
new String[] {"com.twelvemonkeys.imageio.plugins.icns.ICNSImageWriterSpi"},
false, null, null,
null, null,
true, null,
null, null, null
false, null, null, null, null,
true, null, null, null, null
);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Harald Kuhr
* Copyright (c) 2011, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -34,7 +34,6 @@ import com.twelvemonkeys.lang.Validate;
import javax.imageio.stream.ImageInputStream;
import java.awt.*;
import java.awt.image.RenderedImage;
import java.io.IOException;
/**
@@ -47,9 +46,9 @@ import java.io.IOException;
final class IconResource {
// TODO: Rewrite using subclasses/instances!
final long start;
final int type;
final int length;
protected final long start;
protected final int type;
protected final int length;
private IconResource(long start, int type, int length) {
validate(type, length);
@@ -59,12 +58,8 @@ final class IconResource {
this.length = length;
}
static IconResource read(final ImageInputStream input) throws IOException {
return read(input.getStreamPosition(), input);
}
static IconResource read(final long offset, final ImageInputStream input) throws IOException {
return new IconResource(offset, input.readInt(), input.readInt());
public static IconResource read(ImageInputStream input) throws IOException {
return new IconResource(input.getStreamPosition(), input.readInt(), input.readInt());
}
private void validate(int type, int length) {
@@ -118,17 +113,9 @@ final class IconResource {
case ICNS.is32:
case ICNS.il32:
case ICNS.it32:
case ICNS.icp4:
case ICNS.icp5:
case ICNS.icp6:
case ICNS.ic07:
case ICNS.ic08:
case ICNS.ic09:
case ICNS.ic10:
case ICNS.ic11:
case ICNS.ic12:
case ICNS.ic13:
case ICNS.ic14:
if (length > ICNS.RESOURCE_HEADER_SIZE) {
break;
}
@@ -155,7 +142,7 @@ final class IconResource {
);
}
Dimension size() {
public Dimension size() {
switch (type) {
case ICNS.ICON:
case ICNS.ICN_:
@@ -169,14 +156,11 @@ final class IconResource {
case ICNS.ics8:
case ICNS.is32:
case ICNS.s8mk:
case ICNS.icp4:
return new Dimension(16, 16);
case ICNS.icl4:
case ICNS.icl8:
case ICNS.il32:
case ICNS.l8mk:
case ICNS.icp5:
case ICNS.ic11:
return new Dimension(32, 32);
case ICNS.ich_:
case ICNS.ich4:
@@ -184,18 +168,12 @@ final class IconResource {
case ICNS.ih32:
case ICNS.h8mk:
return new Dimension(48, 48);
case ICNS.icp6:
case ICNS.ic12:
return new Dimension(64, 64);
case ICNS.it32:
case ICNS.t8mk:
case ICNS.ic07:
return new Dimension(128, 128);
case ICNS.ic08:
case ICNS.ic13:
return new Dimension(256, 256);
case ICNS.ic09:
case ICNS.ic14:
return new Dimension(512, 512);
case ICNS.ic10:
return new Dimension(1024, 1024);
@@ -204,7 +182,7 @@ final class IconResource {
}
}
int depth() {
public int depth() {
switch (type) {
case ICNS.ICON:
case ICNS.ICN_:
@@ -230,24 +208,16 @@ final class IconResource {
case ICNS.il32:
case ICNS.ih32:
case ICNS.it32:
case ICNS.icp4:
case ICNS.icp5:
case ICNS.icp6:
case ICNS.ic07:
case ICNS.ic08:
case ICNS.ic09:
case ICNS.ic10:
case ICNS.ic11:
case ICNS.ic12:
case ICNS.ic13:
case ICNS.ic14:
return 32;
default:
throw new IllegalStateException(String.format("Unknown icon type: '%s'", ICNSUtil.intToStr(type)));
}
}
boolean isUnknownType() {
public boolean isUnknownType() {
// Unknown types should simply be skipped when reading
switch (type) {
case ICNS.ICON:
@@ -271,24 +241,16 @@ final class IconResource {
case ICNS.il32:
case ICNS.ih32:
case ICNS.it32:
case ICNS.icp4:
case ICNS.icp5:
case ICNS.icp6:
case ICNS.ic07:
case ICNS.ic08:
case ICNS.ic09:
case ICNS.ic10:
case ICNS.ic11:
case ICNS.ic12:
case ICNS.ic13:
case ICNS.ic14:
return false;
}
return true;
}
boolean hasMask() {
public boolean hasMask() {
switch (type) {
case ICNS.ICN_:
case ICNS.icm_:
@@ -300,7 +262,7 @@ final class IconResource {
return false;
}
boolean isMaskType() {
public boolean isMaskType() {
switch (type) {
case ICNS.s8mk:
case ICNS.l8mk:
@@ -312,7 +274,7 @@ final class IconResource {
return false;
}
boolean isCompressed() {
public boolean isCompressed() {
switch (type) {
case ICNS.is32:
case ICNS.il32:
@@ -329,30 +291,18 @@ final class IconResource {
return false;
}
boolean isForeignFormat() {
public boolean isForeignFormat() {
// Recent entries contains full JPEG 2000 or PNG streams
switch (type) {
case ICNS.icp4:
case ICNS.icp5:
case ICNS.icp6:
case ICNS.ic07:
case ICNS.ic08:
case ICNS.ic09:
case ICNS.ic10:
case ICNS.ic11:
case ICNS.ic12:
case ICNS.ic13:
case ICNS.ic14:
return true;
}
return false;
}
boolean isTOC() {
return type == ICNS.TOC_;
}
@Override
public int hashCode() {
return (int) start ^ type;
@@ -372,62 +322,4 @@ final class IconResource {
public String toString() {
return String.format("%s['%s' start: %d, length: %d%s]", getClass().getSimpleName(), ICNSUtil.intToStr(type), start, length, isCompressed() ? " (compressed)" : "");
}
static int typeFromImage(final RenderedImage image, final String compression) {
int width = image.getWidth();
int height = image.getHeight();
if (width == height) {
switch (compression) {
case "JPEG2000":
case "PNG":
return typeFromWidthForeign(width);
case "None":
case "RLE":
return typeFromWidthNative(width);
default:
throw new IllegalArgumentException("Unsupported compression for ICNS: " + compression);
}
}
// Note: Strictly, the format supports an ancient 16x12 size, but I doubt we'll ever support that
throw new IllegalArgumentException(String.format("Unsupported dimensions for ICNS, only square icons supported: %dx%d", width, height));
}
// NOTE: These also needs a mask, if there's an alpha channel
private static int typeFromWidthNative(final int width) {
switch (width) {
case 16:
return ICNS.is32;
case 32:
return ICNS.il32;
case 48:
return ICNS.ih32;
case 128:
return ICNS.it32;
default:
throw new IllegalArgumentException(String.format("Unsupported dimensions for ICNS, only 16, 32, 48 and 128 supported: %dx%d", width, width));
}
}
private static int typeFromWidthForeign(final int width) {
switch (width) {
case 16:
return ICNS.icp4;
case 32:
return ICNS.icp5;
case 64:
return ICNS.icp6;
case 128:
return ICNS.ic07;
case 256:
return ICNS.ic08;
case 512:
return ICNS.ic09;
case 1024:
return ICNS.ic10;
default:
throw new IllegalArgumentException(String.format("Unsupported dimensions for ICNS, only multiples of 2 from 16 to 1024 supported: %dx%d", width, width));
}
}
}
@@ -1 +1 @@
com.twelvemonkeys.imageio.plugins.icns.ICNSImageReaderSpi
com.twelvemonkeys.imageio.plugins.icns.ICNSImageReaderSpi
@@ -1 +0,0 @@
com.twelvemonkeys.imageio.plugins.icns.ICNSImageWriterSpi
@@ -1,189 +0,0 @@
/*
* Copyright (c) 2017, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.icns;
import com.twelvemonkeys.imageio.util.ImageWriterAbstractTest;
import org.junit.Test;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertTrue;
/**
* ICNSImageWriterTest.
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: harald.kuhr$
* @version $Id: ICNSImageWriterTest.java,v 1.0 25/08/2018 harald.kuhr Exp$
*/
public class ICNSImageWriterTest extends ImageWriterAbstractTest {
private final ICNSImageWriterSpi provider = new ICNSImageWriterSpi();
@Override
protected ImageWriter createImageWriter() {
return provider.createWriterInstance(null);
}
@Override
protected List<? extends RenderedImage> getTestData() {
return asList(
new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB),
new BufferedImage(32, 32, BufferedImage.TYPE_BYTE_BINARY),
new BufferedImage(32, 32, BufferedImage.TYPE_BYTE_INDEXED),
new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB),
// new BufferedImage(48, 48, BufferedImage.TYPE_INT_ARGB), // Only supported for compression None/RLE
new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB),
new BufferedImage(128, 128, BufferedImage.TYPE_INT_ARGB),
new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB),
new BufferedImage(512, 512, BufferedImage.TYPE_INT_ARGB),
new BufferedImage(1024, 1024, BufferedImage.TYPE_INT_ARGB)
);
}
@Test(expected = IllegalArgumentException.class)
public void testWriteNonSquare() throws IOException {
// ICNS only supports square icons (except some arcane 16x12 we don't currently support)
ImageWriter writer = createImageWriter();
try (ImageOutputStream stream = ImageIO.createImageOutputStream(new ByteArrayOutputStream())) {
writer.setOutput(stream);
writer.write(new BufferedImage(32, 64, BufferedImage.TYPE_INT_ARGB));
}
finally {
writer.dispose();
}
}
@Test(expected = IllegalArgumentException.class)
public void testWriteBadSize() throws IOException {
// ICNS only supports sizes in multiples of 2 (16, 32, 64, ..., 1024 + 48 and 96)
ImageWriter writer = createImageWriter();
try (ImageOutputStream stream = ImageIO.createImageOutputStream(new ByteArrayOutputStream())) {
writer.setOutput(stream);
writer.write(new BufferedImage(17, 17, BufferedImage.TYPE_INT_ARGB));
}
finally {
writer.dispose();
}
}
@Test
public void testSequencesSupported() {
ImageWriter writer = createImageWriter();
try {
assertTrue(writer.canWriteSequence());
}
finally {
writer.dispose();
}
}
@Test(expected = IllegalStateException.class)
public void testWriteSequenceNotStarted() throws IOException {
// ICNS only supports sizes in multiples of 2 (16, 32, 64, ..., 1024 + 48 and 96)
ImageWriter writer = createImageWriter();
try (ImageOutputStream stream = ImageIO.createImageOutputStream(new ByteArrayOutputStream())) {
writer.setOutput(stream);
BufferedImage image = new BufferedImage(32, 32, BufferedImage.TYPE_INT_ARGB);
writer.writeToSequence(new IIOImage(image, null, null), writer.getDefaultWriteParam());
}
finally {
writer.dispose();
}
}
@Test(expected = IllegalStateException.class)
public void testEndSequenceNotStarted() throws IOException {
// ICNS only supports sizes in multiples of 2 (16, 32, 64, ..., 1024 + 48 and 96)
ImageWriter writer = createImageWriter();
try (ImageOutputStream stream = ImageIO.createImageOutputStream(new ByteArrayOutputStream())) {
writer.setOutput(stream);
writer.endWriteSequence();
}
finally {
writer.dispose();
}
}
@Test(expected = IllegalStateException.class)
public void testPrepareSequenceAlreadyStarted() throws IOException {
// ICNS only supports sizes in multiples of 2 (16, 32, 64, ..., 1024 + 48 and 96)
ImageWriter writer = createImageWriter();
try (ImageOutputStream stream = ImageIO.createImageOutputStream(new ByteArrayOutputStream())) {
writer.setOutput(stream);
writer.prepareWriteSequence(null);
writer.prepareWriteSequence(null);
}
finally {
writer.dispose();
}
}
@Test
public void testWriteSequence() throws IOException {
ImageWriter writer = createImageWriter();
ByteArrayOutputStream output = new ByteArrayOutputStream();
try (ImageOutputStream stream = ImageIO.createImageOutputStream(output)) {
writer.setOutput(stream);
writer.prepareWriteSequence(null);
for (RenderedImage image : getTestData()) {
IIOImage iioImage = new IIOImage(image, null, null);
writer.writeToSequence(iioImage, writer.getDefaultWriteParam());
}
writer.endWriteSequence();
}
finally {
writer.dispose();
}
}
}
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.5</version>
<version>3.4.4-SNAPSHOT</version>
</parent>
<artifactId>imageio-iff</artifactId>
<name>TwelveMonkeys :: ImageIO :: IFF plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.5</version>
<version>3.4.4-SNAPSHOT</version>
</parent>
<artifactId>imageio-jpeg</artifactId>
<name>TwelveMonkeys :: ImageIO :: JPEG plugin</name>
@@ -68,7 +68,10 @@ final class JPEGLosslessDecoder {
private int xLoc;
private int yLoc;
private int mask;
private int[][] outputData;
private int[] outputData;
private int[] outputRedData;
private int[] outputGreenData;
private int[] outputBlueData;
private static final int IDCT_P[] = {
0, 5, 40, 16, 45, 2, 7, 42,
@@ -145,6 +148,8 @@ final class JPEGLosslessDecoder {
int[][] decode() throws IOException {
int current, scanNum = 0;
final int pred[] = new int[10];
int[][] outputRef;
xLoc = 0;
yLoc = 0;
@@ -213,27 +218,32 @@ final class JPEGLosslessDecoder {
xDim = frame.samplesPerLine;
yDim = frame.lines;
outputData = new int[numComp][];
outputRef = new int[numComp][];
for (int componentIndex = 0; componentIndex < numComp; ++componentIndex) {
// not a good use of memory, but I had trouble packing bytes into int. some values exceeded 255.
outputData[componentIndex] = new int[xDim * yDim];
// TODO: Support 4 components (RGBA/YCCA/CMYK/YCCK), others?
if (numComp == 1) {
outputData = new int[xDim * yDim];
outputRef[0] = outputData;
}
else {
outputRedData = new int[xDim * yDim]; // not a good use of memory, but I had trouble packing bytes into int. some values exceeded 255.
outputGreenData = new int[xDim * yDim];
outputBlueData = new int[xDim * yDim];
final int firstValue[] = new int[numComp];
for (int i = 0; i < numComp; i++) {
firstValue[i] = (1 << (precision - 1));
outputRef[0] = outputRedData;
outputRef[1] = outputGreenData;
outputRef[2] = outputBlueData;
}
final int pred[] = new int[numComp];
scanNum++;
while (true) { // Decode one scan
int temp[] = new int[1]; // to store remainder bits
int index[] = new int[1];
System.arraycopy(firstValue, 0, pred, 0, numComp);
for (int i = 0; i < 10; i++) {
pred[i] = (1 << (precision - 1));
}
if (restartInterval == 0) {
current = decode(pred, temp, index);
@@ -275,10 +285,9 @@ final class JPEGLosslessDecoder {
readNumber();
current = input.readUnsignedShort();
}
// TODO oe: 05.05.2018 Is it correct loop? Content of outputData from previous iteration is always lost.
} while ((current != JPEG.EOI) && ((xLoc < xDim) && (yLoc < yDim)) && (scanNum == 0));
return outputData;
return outputRef;
}
private void processWarningOccured(String warning) {
@@ -332,7 +341,7 @@ final class JPEGLosslessDecoder {
return decodeRGB(prev, temp, index);
}
else {
return decodeAny(prev, temp, index);
return -1;
}
}
@@ -344,7 +353,6 @@ final class JPEGLosslessDecoder {
prev[0] = (1 << (frame.samplePrecision - 1));
}
else {
final int[] outputData = this.outputData[0];
switch (selection) {
case 2:
prev[0] = getPreviousY(outputData);
@@ -391,9 +399,6 @@ final class JPEGLosslessDecoder {
}
private int decodeRGB(final int prev[], final int temp[], final int index[]) throws IOException {
final int[] outputRedData = outputData[0];
final int[] outputGreenData = outputData[1];
final int[] outputBlueData = outputData[2];
switch (selection) {
case 2:
prev[0] = getPreviousY(outputRedData);
@@ -432,43 +437,6 @@ final class JPEGLosslessDecoder {
break;
}
return decode0(prev, temp, index);
}
private int decodeAny(final int prev[], final int temp[], final int index[]) throws IOException {
for (int componentIndex = 0; componentIndex < outputData.length; ++componentIndex) {
final int[] outputData = this.outputData[componentIndex];
final int previous;
switch (selection) {
case 2:
previous = getPreviousY(outputData);
break;
case 3:
previous = getPreviousXY(outputData);
break;
case 4:
previous = (getPreviousX(outputData) + getPreviousY(outputData)) - getPreviousXY(outputData);
break;
case 5:
previous = getPreviousX(outputData) + ((getPreviousY(outputData) - getPreviousXY(outputData)) >> 1);
break;
case 6:
previous = getPreviousY(outputData) + ((getPreviousX(outputData) - getPreviousXY(outputData)) >> 1);
break;
case 7:
previous = (int) (((long) getPreviousX(outputData) + getPreviousY(outputData)) / 2);
break;
default:
previous = getPreviousX(outputData);
break;
}
prev[componentIndex] = previous;
}
return decode0(prev, temp, index);
}
private int decode0(int[] prev, int[] temp, int[] index) throws IOException {
int value, actab[], dctab[];
int qtab[];
@@ -726,17 +694,14 @@ final class JPEGLosslessDecoder {
if (numComp == 1) {
outputSingle(pred);
}
else if (numComp == 3) {
outputRGB(pred);
}
else {
outputAny(pred);
outputRGB(pred);
}
}
private void outputSingle(final int pred[]) {
if ((xLoc < xDim) && (yLoc < yDim)) {
outputData[0][(yLoc * xDim) + xLoc] = mask & pred[0];
outputData[(yLoc * xDim) + xLoc] = mask & pred[0];
xLoc++;
if (xLoc >= xDim) {
@@ -748,25 +713,9 @@ final class JPEGLosslessDecoder {
private void outputRGB(final int pred[]) {
if ((xLoc < xDim) && (yLoc < yDim)) {
final int index = (yLoc * xDim) + xLoc;
outputData[0][index] = pred[0];
outputData[1][index] = pred[1];
outputData[2][index] = pred[2];
xLoc++;
if (xLoc >= xDim) {
yLoc++;
xLoc = 0;
}
}
}
private void outputAny(final int pred[]) {
if ((xLoc < xDim) && (yLoc < yDim)) {
final int index = (yLoc * xDim) + xLoc;
for (int componentIndex = 0; componentIndex < outputData.length; ++componentIndex) {
outputData[componentIndex][index] = pred[componentIndex];
}
outputRedData[(yLoc * xDim) + xLoc] = pred[0];
outputGreenData[(yLoc * xDim) + xLoc] = pred[1];
outputBlueData[(yLoc * xDim) + xLoc] = pred[2];
xLoc++;
if (xLoc >= xDim) {
+1 -1
View File
@@ -3,7 +3,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.5</version>
<version>3.4.4-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>imageio-metadata</artifactId>
@@ -83,6 +83,7 @@ public final class PSDReader extends MetadataReader {
PSDResource resource = new PSDResource(id, input);
entries.add(new PSDEntry(id, resource.name(), resource.data()));
}
catch (EOFException e) {
break;
@@ -144,7 +144,6 @@ public interface TIFF {
int TAG_ROWS_PER_STRIP = 278;
int TAG_STRIP_BYTE_COUNTS = 279;
int TAG_FREE_OFFSETS = 288; // "Not recommended for general interchange."
int TAG_FREE_BYTE_COUNTS = 289;
// "Old-style" JPEG (still used as EXIF thumbnail)
int TAG_JPEG_INTERCHANGE_FORMAT = 513;
int TAG_JPEG_INTERCHANGE_FORMAT_LENGTH = 514;
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.5</version>
<version>3.4.4-SNAPSHOT</version>
</parent>
<artifactId>imageio-pcx</artifactId>
<name>TwelveMonkeys :: ImageIO :: PCX plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.5</version>
<version>3.4.4-SNAPSHOT</version>
</parent>
<artifactId>imageio-pdf</artifactId>
<name>TwelveMonkeys :: ImageIO :: PDF plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.5</version>
<version>3.4.4-SNAPSHOT</version>
</parent>
<artifactId>imageio-pict</artifactId>
<name>TwelveMonkeys :: ImageIO :: PICT plugin</name>
@@ -78,7 +78,6 @@ import java.awt.image.*;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
@@ -182,7 +181,7 @@ public final class PICTImageReader extends ImageReaderBase {
readPICTHeader0(pStream);
}
}
private void readPICTHeader0(final ImageInputStream pStream) throws IOException {
// Get size
picSize = pStream.readUnsignedShort();
@@ -326,7 +325,7 @@ public final class PICTImageReader extends ImageReaderBase {
/**
* Reads the PICT stream.
* The contents of the stream will be drawn onto the supplied graphics
* The contents of the stream will be drawn onto the supplied graphics
* object.
* <p>
* If "DEBUG" is true, the elements read are listed on stdout.
@@ -511,7 +510,7 @@ public final class PICTImageReader extends ImageReaderBase {
ovSize.setLocation(x, y);
/*
ovSize.x *= 2;// Don't know why, but has to be multiplied by 2
ovSize.y *= 2;
*/
if (DEBUG) {
@@ -2628,7 +2627,7 @@ public final class PICTImageReader extends ImageReaderBase {
public Iterator<ImageTypeSpecifier> getImageTypes(int pIndex) throws IOException {
// TODO: The images look slightly different in Preview.. Could indicate the color space is wrong...
return Collections.singletonList(
return Arrays.asList(
ImageTypeSpecifiers.createPacked(
ColorSpace.getInstance(ColorSpace.CS_sRGB),
0xff0000, 0xff00, 0xff, 0xff000000, DataBuffer.TYPE_INT, false
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.5</version>
<version>3.4.4-SNAPSHOT</version>
</parent>
<artifactId>imageio-pnm</artifactId>
<name>TwelveMonkeys :: ImageIO :: PNM plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.5</version>
<version>3.4.4-SNAPSHOT</version>
</parent>
<artifactId>imageio-psd</artifactId>
<name>TwelveMonkeys :: ImageIO :: PSD plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.5</version>
<version>3.4.4-SNAPSHOT</version>
</parent>
<artifactId>imageio-reference</artifactId>
<name>TwelveMonkeys :: ImageIO :: reference test cases</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.5</version>
<version>3.4.4-SNAPSHOT</version>
</parent>
<artifactId>imageio-sgi</artifactId>
<name>TwelveMonkeys :: ImageIO :: SGI plugin</name>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio</artifactId>
<version>3.5</version>
<version>3.4.4-SNAPSHOT</version>
</parent>
<artifactId>imageio-tga</artifactId>
<name>TwelveMonkeys :: ImageIO :: TGA plugin</name>
@@ -36,8 +36,6 @@ interface TGA {
/** Fixed header size: 18.*/
int HEADER_SIZE = 18;
int EXT_AREA_SIZE = 495;
/** No color map included. */
int COLORMAP_NONE = 0;
/** Color map included. */
@@ -36,8 +36,6 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Calendar;
import static com.twelvemonkeys.imageio.plugins.tga.TGA.EXT_AREA_SIZE;
/**
* TGAExtensions.
*
@@ -46,6 +44,7 @@ import static com.twelvemonkeys.imageio.plugins.tga.TGA.EXT_AREA_SIZE;
* @version $Id: TGAExtensions.java,v 1.0 27/07/15 harald.kuhr Exp$
*/
final class TGAExtensions {
public static final int EXT_AREA_SIZE = 495;
private String authorName;
private String authorComments;
@@ -78,7 +77,7 @@ final class TGAExtensions {
}
TGAExtensions extensions = new TGAExtensions();
extensions.authorName = readString(stream, 41);
extensions.authorName = readString(stream, 41);;
extensions.authorComments = readString(stream, 324);
extensions.creationDate = readDate(stream);
extensions.jobId = readString(stream, 41);

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