mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2026-05-19 00:00:03 -04:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c709fcafa9 | |||
| 4f6ed55218 | |||
| ae7e3d8c9b | |||
| 43ddc84986 | |||
| e682696fac | |||
| 5f190ea57d | |||
| 3ca37e4b8c | |||
| a30a032a9c | |||
| 77ebba4f7d | |||
| 456749ded8 | |||
| 47a26651b4 | |||
| 10183ef830 | |||
| 263fb75d1d | |||
| e61ec45737 | |||
| 6e063f263c | |||
| e2cf529000 | |||
| 9d1c418d8d |
@@ -35,7 +35,7 @@ jobs:
|
||||
- name: Run Tests
|
||||
run: mvn --batch-mode --no-transfer-progress test
|
||||
- name: Publish Test Report
|
||||
uses: mikepenz/action-junit-report@74626db7353a25a20a72816467ebf035f674c5f8 # v5
|
||||
uses: mikepenz/action-junit-report@bccf2e31636835cf0874589931c4116687171386 # v5
|
||||
if: ${{ !cancelled() }}
|
||||
with:
|
||||
report_paths: "**/target/surefire-reports/TEST*.xml"
|
||||
@@ -57,7 +57,7 @@ jobs:
|
||||
- name: Run Tests
|
||||
run: mvn --batch-mode --no-transfer-progress test
|
||||
- name: Publish Test Report
|
||||
uses: mikepenz/action-junit-report@74626db7353a25a20a72816467ebf035f674c5f8 # v5
|
||||
uses: mikepenz/action-junit-report@bccf2e31636835cf0874589931c4116687171386 # v5
|
||||
if: ${{ !cancelled() }}
|
||||
with:
|
||||
report_paths: "**/target/surefire-reports/TEST*.xml"
|
||||
@@ -91,7 +91,7 @@ jobs:
|
||||
- name: Run Tests
|
||||
run: mvn --batch-mode --no-transfer-progress test
|
||||
- name: Publish Test Report
|
||||
uses: mikepenz/action-junit-report@74626db7353a25a20a72816467ebf035f674c5f8 # v5
|
||||
uses: mikepenz/action-junit-report@bccf2e31636835cf0874589931c4116687171386 # v5
|
||||
if: ${{ !cancelled() }}
|
||||
with:
|
||||
report_paths: "**/target/surefire-reports/TEST*.xml"
|
||||
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
|
||||
uses: github/codeql-action/init@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
@@ -51,7 +51,7 @@ jobs:
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
|
||||
uses: github/codeql-action/autobuild@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
@@ -64,6 +64,6 @@ jobs:
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
|
||||
uses: github/codeql-action/analyze@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||
# format to the repository Actions tab.
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
@@ -57,6 +57,6 @@ jobs:
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v4.32.4
|
||||
uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
@@ -284,20 +284,6 @@ abstract class AbstractDecoratedMap<K, V> extends AbstractMap<K, V> implements M
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
// NOTE: Extra cautions is taken, to only remove the entry if it
|
||||
// equals the entry in the map
|
||||
Object key = ((Entry) o).getKey();
|
||||
Entry entry = (Entry) entries.get(key);
|
||||
|
||||
// Same entry?
|
||||
if (entry != null && entry.equals(o)) {
|
||||
return AbstractWrappedMap.this.remove(key) != null;
|
||||
}
|
||||
|
||||
return false;
|
||||
*/
|
||||
|
||||
//noinspection unchecked
|
||||
return AbstractDecoratedMap.this.removeEntry((Entry) o) != null;
|
||||
}
|
||||
@@ -322,7 +308,7 @@ abstract class AbstractDecoratedMap<K, V> extends AbstractMap<K, V> implements M
|
||||
return containsKey(o);
|
||||
}
|
||||
public boolean remove(Object o) {
|
||||
return AbstractDecoratedMap.this.remove(o) != null;
|
||||
return AbstractDecoratedMap.this.removeEntry(getEntry((K) o)) != null;
|
||||
}
|
||||
public void clear() {
|
||||
AbstractDecoratedMap.this.clear();
|
||||
|
||||
@@ -137,43 +137,43 @@ public final class BeanMap extends AbstractMap<String, Object> implements Serial
|
||||
}
|
||||
|
||||
private class BeanIterator implements Iterator<Entry<String, Object>> {
|
||||
private final Iterator<PropertyDescriptor> mIterator;
|
||||
private final Iterator<PropertyDescriptor> iterator;
|
||||
|
||||
public BeanIterator(final Iterator<PropertyDescriptor> pIterator) {
|
||||
mIterator = pIterator;
|
||||
iterator = pIterator;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
return mIterator.hasNext();
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
public BeanEntry next() {
|
||||
return new BeanEntry(mIterator.next());
|
||||
return new BeanEntry(iterator.next());
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
mIterator.remove();
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
private class BeanEntry implements Entry<String, Object> {
|
||||
private final PropertyDescriptor mDescriptor;
|
||||
private final PropertyDescriptor descriptor;
|
||||
|
||||
public BeanEntry(final PropertyDescriptor pDescriptor) {
|
||||
this.mDescriptor = pDescriptor;
|
||||
this.descriptor = pDescriptor;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return mDescriptor.getName();
|
||||
return descriptor.getName();
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return unwrap(new Wrapped() {
|
||||
public Object run() throws IllegalAccessException, InvocationTargetException {
|
||||
final Method method = mDescriptor.getReadMethod();
|
||||
final Method method = descriptor.getReadMethod();
|
||||
// A write-only bean.
|
||||
if (method == null) {
|
||||
throw new UnsupportedOperationException("No getter: " + mDescriptor.getName());
|
||||
throw new UnsupportedOperationException("No getter: " + descriptor.getName());
|
||||
}
|
||||
|
||||
return method.invoke(bean);
|
||||
@@ -184,10 +184,10 @@ public final class BeanMap extends AbstractMap<String, Object> implements Serial
|
||||
public Object setValue(final Object pValue) {
|
||||
return unwrap(new Wrapped() {
|
||||
public Object run() throws IllegalAccessException, InvocationTargetException {
|
||||
final Method method = mDescriptor.getWriteMethod();
|
||||
final Method method = descriptor.getWriteMethod();
|
||||
// A read-only bean.
|
||||
if (method == null) {
|
||||
throw new UnsupportedOperationException("No write method for property: " + mDescriptor.getName());
|
||||
throw new UnsupportedOperationException("No write method for property: " + descriptor.getName());
|
||||
}
|
||||
|
||||
final Object old = getValue();
|
||||
|
||||
@@ -71,7 +71,6 @@ public abstract class ObjectAbstractTest {
|
||||
// TODO: What more can we test?
|
||||
}
|
||||
|
||||
// TODO: assert that either BOTH or NONE of equals/hashcode is overridden
|
||||
@Test
|
||||
public void testEqualsHashCode(){
|
||||
Object obj = makeObject();
|
||||
@@ -328,5 +327,4 @@ public abstract class ObjectAbstractTest {
|
||||
return new Cloneable() {};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
|
||||
package com.twelvemonkeys.util;
|
||||
|
||||
import org.junit.jupiter.api.Nested;
|
||||
|
||||
import java.beans.IntrospectionException;
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
@@ -172,4 +174,16 @@ public class BeanMapTest extends MapAbstractTest {
|
||||
}
|
||||
|
||||
static class NullBean implements Serializable { }
|
||||
|
||||
@Nested
|
||||
public class TestBeanMapEntrySet extends TestMapEntrySet {
|
||||
}
|
||||
|
||||
@Nested
|
||||
public class TestBeanMapKeySet extends TestMapKeySet {
|
||||
}
|
||||
|
||||
@Nested
|
||||
public class TestBeanMapValues extends TestMapValues {
|
||||
}
|
||||
}
|
||||
|
||||
+16
-17
@@ -436,24 +436,24 @@ public abstract class CollectionAbstractTest extends ObjectAbstractTest {
|
||||
*/
|
||||
public Object[] getFullNonNullElements() {
|
||||
return new Object[] {
|
||||
new String(""),
|
||||
new String("One"),
|
||||
new Integer(2),
|
||||
"Three",
|
||||
new Integer(4),
|
||||
"",
|
||||
"One",
|
||||
new Double(5),
|
||||
new Float(6),
|
||||
2,
|
||||
"Three",
|
||||
4,
|
||||
"One",
|
||||
5.0,
|
||||
6F,
|
||||
"Seven",
|
||||
"Eight",
|
||||
new String("Nine"),
|
||||
new Integer(10),
|
||||
new Short((short)11),
|
||||
new Long(12),
|
||||
"Nine",
|
||||
10,
|
||||
(short) 11,
|
||||
12L,
|
||||
"Thirteen",
|
||||
"14",
|
||||
"15",
|
||||
new Byte((byte)16)
|
||||
(byte) 16
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1149,7 +1149,7 @@ public abstract class CollectionAbstractTest extends ObjectAbstractTest {
|
||||
public void testUnsupportedRemove() {
|
||||
if (isRemoveSupported()) return;
|
||||
|
||||
resetEmpty();
|
||||
resetFull();
|
||||
try {
|
||||
collection.clear();
|
||||
fail("clear should raise UnsupportedOperationException");
|
||||
@@ -1159,7 +1159,7 @@ public abstract class CollectionAbstractTest extends ObjectAbstractTest {
|
||||
verifyAll();
|
||||
|
||||
try {
|
||||
collection.remove(null);
|
||||
collection.remove(getFullElements()[0]);
|
||||
fail("remove should raise UnsupportedOperationException");
|
||||
} catch (UnsupportedOperationException e) {
|
||||
// expected
|
||||
@@ -1167,7 +1167,7 @@ public abstract class CollectionAbstractTest extends ObjectAbstractTest {
|
||||
verifyAll();
|
||||
|
||||
try {
|
||||
collection.removeAll(null);
|
||||
collection.removeAll(Arrays.asList(getFullElements()));
|
||||
fail("removeAll should raise UnsupportedOperationException");
|
||||
} catch (UnsupportedOperationException e) {
|
||||
// expected
|
||||
@@ -1175,7 +1175,7 @@ public abstract class CollectionAbstractTest extends ObjectAbstractTest {
|
||||
verifyAll();
|
||||
|
||||
try {
|
||||
collection.retainAll(null);
|
||||
collection.retainAll(Collections.emptySet());
|
||||
fail("removeAll should raise UnsupportedOperationException");
|
||||
} catch (UnsupportedOperationException e) {
|
||||
// expected
|
||||
@@ -1192,7 +1192,6 @@ public abstract class CollectionAbstractTest extends ObjectAbstractTest {
|
||||
// expected
|
||||
}
|
||||
verifyAll();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -212,5 +212,17 @@ public class LRUMapTest extends LinkedMapTest {
|
||||
list.add(pEntry.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
public class TestLRUMapEntrySet extends TestMapEntrySet {
|
||||
}
|
||||
|
||||
@Nested
|
||||
public class TestLRUMapKeySet extends TestMapKeySet {
|
||||
}
|
||||
|
||||
@Nested
|
||||
public class TestLRUMapValues extends TestMapValues {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -201,4 +201,16 @@ public class LinkedMapTest extends MapAbstractTest {
|
||||
public void tearDown() throws Exception {
|
||||
labRat = null;
|
||||
}
|
||||
|
||||
@Nested
|
||||
public class TestLinkedMapEntrySet extends TestMapEntrySet {
|
||||
}
|
||||
|
||||
@Nested
|
||||
public class TestLinkedMapKeySet extends TestMapKeySet {
|
||||
}
|
||||
|
||||
@Nested
|
||||
public class TestLinkedMapValues extends TestMapValues {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1255,7 +1255,7 @@ public abstract class MapAbstractTest extends ObjectAbstractTest {
|
||||
}
|
||||
*/
|
||||
|
||||
public class TestMapEntrySet extends SetAbstractTest {
|
||||
protected abstract class TestMapEntrySet extends SetAbstractTest {
|
||||
|
||||
// Have to implement manually; entrySet doesn't support addAll
|
||||
public Object[] getFullElements() {
|
||||
@@ -1429,7 +1429,7 @@ public abstract class MapAbstractTest extends ObjectAbstractTest {
|
||||
}
|
||||
*/
|
||||
|
||||
public class TestMapKeySet extends SetAbstractTest {
|
||||
protected abstract class TestMapKeySet extends SetAbstractTest {
|
||||
public Object[] getFullElements() {
|
||||
return getSampleKeys();
|
||||
}
|
||||
@@ -1495,7 +1495,7 @@ public abstract class MapAbstractTest extends ObjectAbstractTest {
|
||||
}
|
||||
*/
|
||||
|
||||
public class TestMapValues extends CollectionAbstractTest {
|
||||
protected abstract class TestMapValues extends CollectionAbstractTest {
|
||||
public Object[] getFullElements() {
|
||||
return getSampleValues();
|
||||
}
|
||||
|
||||
@@ -668,5 +668,17 @@ public class TimeoutMapTest extends MapAbstractTest {
|
||||
assertFalse(timeoutMap.containsKey("xyz"));
|
||||
assertNull(timeoutMap.get("xyz"));
|
||||
}
|
||||
|
||||
@Nested
|
||||
public class TestTimeoutMapEntrySet extends TestMapEntrySet {
|
||||
}
|
||||
|
||||
@Nested
|
||||
public class TestTimeoutMapKeySet extends TestMapKeySet {
|
||||
}
|
||||
|
||||
@Nested
|
||||
public class TestTimeoutMapValues extends TestMapValues {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<junit.jupiter.version>5.14.3</junit.jupiter.version>
|
||||
<junit.jupiter.version>5.14.4</junit.jupiter.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
</description>
|
||||
|
||||
<properties>
|
||||
<junit.jupiter.version>5.14.3</junit.jupiter.version>
|
||||
<junit.jupiter.version>5.14.4</junit.jupiter.version>
|
||||
</properties>
|
||||
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.21.0</version>
|
||||
<version>2.22.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
+11
-24
@@ -32,6 +32,7 @@ package com.twelvemonkeys.imageio.plugins.bmp;
|
||||
|
||||
import com.twelvemonkeys.imageio.stream.SubImageOutputStream;
|
||||
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
||||
import com.twelvemonkeys.imageio.util.SequenceSupport;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.IIOImage;
|
||||
@@ -64,7 +65,7 @@ public final class ICOImageWriter extends DIBImageWriter {
|
||||
private static final int ICO_MAX_DIMENSION = 256;
|
||||
private static final int INITIAL_ENTRY_COUNT = 8;
|
||||
|
||||
private int sequenceIndex = -1;
|
||||
private final SequenceSupport sequence = new SequenceSupport();
|
||||
|
||||
private ImageWriter pngDelegate;
|
||||
|
||||
@@ -74,7 +75,7 @@ public final class ICOImageWriter extends DIBImageWriter {
|
||||
|
||||
@Override
|
||||
protected void resetMembers() {
|
||||
sequenceIndex = -1;
|
||||
sequence.reset();
|
||||
|
||||
if (pngDelegate != null) {
|
||||
pngDelegate.dispose();
|
||||
@@ -107,16 +108,12 @@ public final class ICOImageWriter extends DIBImageWriter {
|
||||
@Override
|
||||
public void prepareWriteSequence(final IIOMetadata streamMetadata) throws IOException {
|
||||
assertOutput();
|
||||
|
||||
if (sequenceIndex >= 0) {
|
||||
throw new IllegalStateException("writeSequence already started");
|
||||
}
|
||||
sequence.start();
|
||||
|
||||
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...
|
||||
@@ -130,27 +127,19 @@ public final class ICOImageWriter extends DIBImageWriter {
|
||||
@Override
|
||||
public void endWriteSequence() {
|
||||
assertOutput();
|
||||
|
||||
if (sequenceIndex < 0) {
|
||||
throw new IllegalStateException("prepareWriteSequence not called");
|
||||
}
|
||||
|
||||
sequenceIndex = -1;
|
||||
sequence.end();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToSequence(final IIOImage image, final ImageWriteParam param) throws IOException {
|
||||
assertOutput();
|
||||
|
||||
if (sequenceIndex < 0) {
|
||||
throw new IllegalStateException("prepareWriteSequence not called");
|
||||
}
|
||||
int imageIndex = sequence.advance();
|
||||
|
||||
if (image.hasRaster()) {
|
||||
throw new UnsupportedOperationException("Raster not supported");
|
||||
}
|
||||
|
||||
if (sequenceIndex >= INITIAL_ENTRY_COUNT) {
|
||||
if (imageIndex >= INITIAL_ENTRY_COUNT) {
|
||||
growIfNecessary();
|
||||
}
|
||||
|
||||
@@ -172,7 +161,7 @@ public final class ICOImageWriter extends DIBImageWriter {
|
||||
// Uncompressed, RLE4/RLE8 or PNG compressed
|
||||
boolean pngCompression = param != null && "BI_PNG".equals(param.getCompressionType());
|
||||
|
||||
processImageStarted(sequenceIndex);
|
||||
processImageStarted(imageIndex);
|
||||
|
||||
if (pngCompression) {
|
||||
// NOTE: Embedding a PNG in a ICO is slightly different than a BMP with BI_PNG compression,
|
||||
@@ -198,17 +187,15 @@ public final class ICOImageWriter extends DIBImageWriter {
|
||||
|
||||
// Update count
|
||||
imageOutput.seek(4);
|
||||
imageOutput.writeShort(sequenceIndex + 1);
|
||||
imageOutput.writeShort(imageIndex + 1);
|
||||
|
||||
// Write entry
|
||||
int entryPosition = 6 + sequenceIndex * ENTRY_SIZE;
|
||||
int entryPosition = 6 + imageIndex * ENTRY_SIZE;
|
||||
imageOutput.seek(entryPosition);
|
||||
|
||||
long size = nextPosition - imageOffset;
|
||||
writeEntry(width, height, colorModel, (int) size, (int) imageOffset);
|
||||
|
||||
sequenceIndex++;
|
||||
|
||||
imageOutput.seek(nextPosition);
|
||||
}
|
||||
|
||||
@@ -265,7 +252,7 @@ public final class ICOImageWriter extends DIBImageWriter {
|
||||
pngDelegate.addIIOWriteWarningListener(new IIOWriteWarningListener() {
|
||||
@Override
|
||||
public void warningOccurred(ImageWriter source, int imageIndex, String warning) {
|
||||
processWarningOccurred(sequenceIndex, warning);
|
||||
processWarningOccurred(sequence.current(), warning);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2026, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.twelvemonkeys.imageio.util;
|
||||
|
||||
import javax.imageio.IIOImage;
|
||||
import javax.imageio.ImageWriteParam;
|
||||
import javax.imageio.ImageWriter;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
|
||||
/**
|
||||
* A tiny utility class that keeps state for sequences.
|
||||
* For use by {@code ImageWriter} implementations that supports sequence (multiple images in same stream).
|
||||
*
|
||||
* @see ImageWriter#canWriteSequence()
|
||||
*/
|
||||
public final class SequenceSupport {
|
||||
// Initial state, no sequence running
|
||||
private int index = -1;
|
||||
|
||||
/**
|
||||
* Resets the sequence to initial state, regardless of the current sequence state.
|
||||
*/
|
||||
public void reset() {
|
||||
index = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a new sequence.
|
||||
*
|
||||
* @throws IllegalStateException if a sequence is already running.
|
||||
* @see ImageWriter#prepareWriteSequence(IIOMetadata)
|
||||
*/
|
||||
public void start() {
|
||||
if (index >= 0) {
|
||||
throw new IllegalStateException("prepareWriteSequence already invoked");
|
||||
}
|
||||
|
||||
index = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Advances the current sequence.
|
||||
*
|
||||
* @return the current sequence index.
|
||||
* @throws IllegalStateException if a sequence is not running.
|
||||
* @see ImageWriter#writeToSequence(IIOImage, ImageWriteParam)
|
||||
*/
|
||||
public int advance() {
|
||||
if (index < 0) {
|
||||
throw new IllegalStateException("prepareWriteSequence not invoked");
|
||||
}
|
||||
|
||||
return index++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current sequence index.
|
||||
*
|
||||
* @return the current sequence index, or {@code -1} if a sequence is not running.
|
||||
*/
|
||||
public int current() {
|
||||
// This method does not throw IllegalStateException, to allow
|
||||
// ImageWriters to use the index in cases that may or may not
|
||||
// happen "inside" a sequence.
|
||||
// I'm not entirely sure if this is a good idea...
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends the current sequence.
|
||||
* The sequence is reset to initial state, and a new sequence may be started.
|
||||
*
|
||||
* @return the current (last) sequence index
|
||||
* @throws IllegalStateException if a sequence is not running.
|
||||
* @see ImageWriter#endWriteSequence()
|
||||
*/
|
||||
public int end() {
|
||||
if (index < 0) {
|
||||
throw new IllegalStateException("prepareWriteSequence not invoked");
|
||||
}
|
||||
|
||||
int last = index;
|
||||
index = -1;
|
||||
|
||||
return last;
|
||||
}
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
package com.twelvemonkeys.imageio.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class SequenceSupportTest {
|
||||
@Test
|
||||
void happyCase() {
|
||||
SequenceSupport sequence = new SequenceSupport();
|
||||
|
||||
sequence.start();
|
||||
assertEquals(0, sequence.current());
|
||||
|
||||
for (int i = 0; i < Byte.MAX_VALUE; i++) {
|
||||
assertEquals(i, sequence.advance());
|
||||
assertEquals(i + 1, sequence.current());
|
||||
}
|
||||
|
||||
assertEquals(127, sequence.end());
|
||||
assertEquals(-1, sequence.current());
|
||||
assertThrows(IllegalStateException.class, sequence::advance);
|
||||
}
|
||||
|
||||
@Test
|
||||
void reset() {
|
||||
SequenceSupport sequence = new SequenceSupport();
|
||||
sequence.reset();
|
||||
|
||||
assertEquals(-1, sequence.current());
|
||||
assertThrows(IllegalStateException.class, sequence::end);
|
||||
|
||||
sequence.start();
|
||||
sequence.reset();
|
||||
|
||||
assertEquals(-1, sequence.current());
|
||||
assertThrows(IllegalStateException.class, sequence::end);
|
||||
|
||||
sequence.start();
|
||||
sequence.advance();
|
||||
sequence.reset();
|
||||
|
||||
assertEquals(-1, sequence.current());
|
||||
assertThrows(IllegalStateException.class, sequence::end);
|
||||
|
||||
sequence.start();
|
||||
sequence.end();
|
||||
sequence.reset();
|
||||
|
||||
assertEquals(-1, sequence.current());
|
||||
assertThrows(IllegalStateException.class, sequence::end);
|
||||
}
|
||||
|
||||
@Test
|
||||
void startEnd() {
|
||||
SequenceSupport sequence = new SequenceSupport();
|
||||
sequence.start();
|
||||
sequence.end();
|
||||
|
||||
assertEquals(-1, sequence.current());
|
||||
assertThrows(IllegalStateException.class, sequence::end);
|
||||
}
|
||||
|
||||
@Test
|
||||
void startAlreadyStarted() {
|
||||
SequenceSupport sequence = new SequenceSupport();
|
||||
sequence.start();
|
||||
|
||||
assertThrows(IllegalStateException.class, sequence::start);
|
||||
}
|
||||
|
||||
@Test
|
||||
void advanceNotStarted() {
|
||||
SequenceSupport sequence = new SequenceSupport();
|
||||
assertThrows(IllegalStateException.class, sequence::advance);
|
||||
}
|
||||
|
||||
@Test
|
||||
void currentNotStarted() {
|
||||
SequenceSupport sequence = new SequenceSupport();
|
||||
assertEquals(-1, sequence.current());
|
||||
}
|
||||
|
||||
@Test
|
||||
void endNotStarted() {
|
||||
SequenceSupport sequence = new SequenceSupport();
|
||||
assertThrows(IllegalStateException.class, sequence::end);
|
||||
}
|
||||
}
|
||||
+12
-18
@@ -47,9 +47,12 @@ import java.awt.Dimension;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @see <a href="https://learn.microsoft.com/en-us/windows/win32/direct3ddds/dds-header">DDS_HEADER structure</a>
|
||||
* @see <a href="https://learn.microsoft.com/en-us/windows/win32/direct3ddds/dx-graphics-dds-pguide">Programming Guide for DDS</a>
|
||||
*/
|
||||
final class DDSHeader {
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/direct3ddds/dx-graphics-dds-pguide
|
||||
private int flags;
|
||||
|
||||
private int mipMapCount;
|
||||
@@ -69,26 +72,16 @@ final class DDSHeader {
|
||||
static DDSHeader read(final ImageInputStream imageInput) throws IOException {
|
||||
DDSHeader header = new DDSHeader();
|
||||
|
||||
// Read MAGIC bytes [0,3]
|
||||
int magic = imageInput.readInt();
|
||||
if (magic != DDS.MAGIC) {
|
||||
throw new IIOException(String.format("Not a DDS file. Expected DDS magic 0x%8x', read 0x%8x", DDS.MAGIC, magic));
|
||||
}
|
||||
|
||||
// DDS_HEADER structure
|
||||
// https://learn.microsoft.com/en-us/windows/win32/direct3ddds/dds-header
|
||||
int dwSize = imageInput.readInt(); // [4,7]
|
||||
if (dwSize != DDS.HEADER_SIZE) {
|
||||
throw new IIOException(String.format("Invalid DDS header size (expected %d): %d", DDS.HEADER_SIZE, dwSize));
|
||||
}
|
||||
|
||||
// Verify setFlags
|
||||
// Verify flags
|
||||
header.flags = imageInput.readInt(); // [8,11]
|
||||
if (!header.getFlag(DDS.FLAG_CAPS
|
||||
| DDS.FLAG_HEIGHT
|
||||
| DDS.FLAG_WIDTH
|
||||
| DDS.FLAG_PIXELFORMAT)) {
|
||||
throw new IIOException("Required DDS Flag missing in header: " + Integer.toBinaryString(header.flags));
|
||||
if (!header.hasFlag(DDS.FLAG_CAPS | DDS.FLAG_HEIGHT | DDS.FLAG_WIDTH | DDS.FLAG_PIXELFORMAT)) {
|
||||
// NOTE: The Microsoft DDS documentation mention that readers should not rely on these flags...
|
||||
throw new IIOException("Required DDS flag missing in header: " + Integer.toBinaryString(header.flags));
|
||||
}
|
||||
|
||||
// Read Height & Width
|
||||
@@ -109,7 +102,7 @@ final class DDSHeader {
|
||||
// DDS_PIXELFORMAT structure
|
||||
int px_dwSize = imageInput.readInt(); // [76,79]
|
||||
if (px_dwSize != DDS.PIXELFORMAT_SIZE) {
|
||||
throw new IIOException(String.format("Invalid DDS PIXELFORMAT size (expected %d): %d", DDS.PIXELFORMAT_SIZE, dwSize));
|
||||
throw new IIOException(String.format("Invalid DDS pixel format structure size (expected %d): %d", DDS.PIXELFORMAT_SIZE, dwSize));
|
||||
}
|
||||
|
||||
header.pixelFormatFlags = imageInput.readInt(); // [80,83]
|
||||
@@ -128,6 +121,7 @@ final class DDSHeader {
|
||||
int dwReserved2 = imageInput.readInt(); // [124,127]
|
||||
|
||||
if (header.fourCC == DDSType.DXT10.fourCC()) {
|
||||
// If DXT10, the DXT10 header will follow immediately
|
||||
header.dxt10Header = DXT10Header.read(imageInput);
|
||||
}
|
||||
|
||||
@@ -146,8 +140,8 @@ final class DDSHeader {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean getFlag(int mask) {
|
||||
return (flags & mask) != 0;
|
||||
private boolean hasFlag(int mask) {
|
||||
return (flags & mask) == mask;
|
||||
}
|
||||
|
||||
int getWidth(int imageIndex) {
|
||||
|
||||
-1
@@ -77,5 +77,4 @@ final class DDSImageMetadata extends StandardImageMetadataSupport {
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
@@ -33,6 +33,7 @@ package com.twelvemonkeys.imageio.plugins.dds;
|
||||
import com.twelvemonkeys.imageio.ImageReaderBase;
|
||||
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
@@ -167,6 +168,12 @@ public final class DDSImageReader extends ImageReaderBase {
|
||||
private void readHeader() throws IOException {
|
||||
if (header == null) {
|
||||
imageInput.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
||||
|
||||
int magic = imageInput.readInt();
|
||||
if (magic != DDS.MAGIC) {
|
||||
throw new IIOException(String.format("Not a DDS file. Expected DDS magic 0x%8x', read 0x%8x", DDS.MAGIC, magic));
|
||||
}
|
||||
|
||||
header = DDSHeader.read(imageInput);
|
||||
imageInput.flushBefore(imageInput.getStreamPosition());
|
||||
}
|
||||
|
||||
+24
-33
@@ -2,6 +2,7 @@ package com.twelvemonkeys.imageio.plugins.dds;
|
||||
|
||||
import com.twelvemonkeys.imageio.ImageWriterBase;
|
||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||
import com.twelvemonkeys.imageio.util.SequenceSupport;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.IIOImage;
|
||||
@@ -29,9 +30,9 @@ import java.nio.file.Paths;
|
||||
*/
|
||||
class DDSImageWriter extends ImageWriterBase {
|
||||
|
||||
private long startPos;
|
||||
// TODO: Create a SequenceSupport class that handles sequence prepare/write/end
|
||||
private int mipmapIndex = -1;
|
||||
private final SequenceSupport mipmapSequence = new SequenceSupport();
|
||||
|
||||
private long headerStartPos;
|
||||
private DDSType mipmapType;
|
||||
private Dimension mipmapDimension;
|
||||
|
||||
@@ -46,7 +47,8 @@ class DDSImageWriter extends ImageWriterBase {
|
||||
|
||||
@Override
|
||||
protected void resetMembers() {
|
||||
mipmapIndex = -1;
|
||||
headerStartPos = 0;
|
||||
mipmapSequence.reset();
|
||||
mipmapType = null;
|
||||
mipmapDimension = null;
|
||||
}
|
||||
@@ -64,30 +66,22 @@ class DDSImageWriter extends ImageWriterBase {
|
||||
@Override
|
||||
public void prepareWriteSequence(IIOMetadata streamMetadata) throws IOException {
|
||||
assertOutput();
|
||||
mipmapSequence.start();
|
||||
|
||||
if (mipmapIndex >= 0) {
|
||||
throw new IllegalStateException("writeSequence already started");
|
||||
}
|
||||
mipmapIndex = 0;
|
||||
|
||||
startPos = imageOutput.getStreamPosition();
|
||||
imageOutput.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
||||
imageOutput.writeInt(DDS.MAGIC);
|
||||
imageOutput.flush();
|
||||
|
||||
headerStartPos = imageOutput.getStreamPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endWriteSequence() throws IOException {
|
||||
assertOutput();
|
||||
int mipmapCount = mipmapSequence.end();
|
||||
|
||||
if (mipmapIndex < 0) {
|
||||
throw new IllegalStateException("prepareWriteSequence not called");
|
||||
}
|
||||
// Go back and update header
|
||||
updateHeader(mipmapCount);
|
||||
|
||||
// Go back and update hader
|
||||
updateHeader(mipmapIndex);
|
||||
|
||||
mipmapIndex = -1;
|
||||
mipmapType = null;
|
||||
mipmapDimension = null;
|
||||
|
||||
@@ -103,13 +97,12 @@ class DDSImageWriter extends ImageWriterBase {
|
||||
|
||||
@Override
|
||||
public void writeToSequence(IIOImage image, ImageWriteParam param) throws IOException {
|
||||
if (mipmapIndex < 0) {
|
||||
throw new IllegalStateException("prepareWriteSequence not called");
|
||||
}
|
||||
int mipmapIndex = mipmapSequence.advance();
|
||||
|
||||
Raster raster = getRaster(image);
|
||||
ensureImageChannels(raster);
|
||||
ensureTextureDimension(raster);
|
||||
mipmapDimension = new Dimension(raster.getWidth(), raster.getHeight());
|
||||
|
||||
DDSImageWriteParam ddsParam = param instanceof DDSImageWriteParam
|
||||
? ((DDSImageWriteParam) param)
|
||||
@@ -120,7 +113,7 @@ class DDSImageWriter extends ImageWriterBase {
|
||||
mipmapType = type;
|
||||
}
|
||||
else if (type != mipmapType) {
|
||||
processWarningOccurred(mipmapIndex, "All images in DDS MipMap must use same pixel format and compression");
|
||||
processWarningOccurred(mipmapIndex, "All images in DDS mipmap must use same pixel format and compression");
|
||||
}
|
||||
if (mipmapType == null) {
|
||||
throw new IIOException("Only compressed DDS using DXT1-5 or DXT10 with block compression is currently supported");
|
||||
@@ -140,9 +133,6 @@ class DDSImageWriter extends ImageWriterBase {
|
||||
|
||||
processImageProgress(100f);
|
||||
processImageComplete();
|
||||
|
||||
mipmapDimension = new Dimension(raster.getWidth(), raster.getHeight());
|
||||
mipmapIndex++;
|
||||
}
|
||||
|
||||
private static Raster getRaster(IIOImage image) throws IIOException {
|
||||
@@ -210,7 +200,7 @@ class DDSImageWriter extends ImageWriterBase {
|
||||
//dwDepth
|
||||
imageOutput.writeInt(0);
|
||||
//dwMipmapCount
|
||||
imageOutput.writeInt(1);
|
||||
imageOutput.writeInt(1); // Should probably write 0 here for non-mipmap?
|
||||
//reserved
|
||||
imageOutput.write(new byte[44]);
|
||||
//pixFmt
|
||||
@@ -230,7 +220,7 @@ class DDSImageWriter extends ImageWriterBase {
|
||||
}
|
||||
|
||||
long streamPosition = imageOutput.getStreamPosition();
|
||||
imageOutput.seek(startPos + 8); // Seek back to start + 4 magic + 4 header size
|
||||
imageOutput.seek(headerStartPos + 4); // Seek back to header start, skip 4 byte header size
|
||||
|
||||
int flags = imageOutput.readInt();
|
||||
imageOutput.seek(imageOutput.getStreamPosition() - 4);
|
||||
@@ -268,15 +258,14 @@ class DDSImageWriter extends ImageWriterBase {
|
||||
//dwRGBBitCount
|
||||
imageOutput.writeInt(type.blockSize() * 8); // TODO: Is bitcount always a multiple of 8?
|
||||
|
||||
int[] mask = type.rgbaMasks;
|
||||
//dwRBitMask
|
||||
imageOutput.writeInt(mask[0]);
|
||||
imageOutput.writeInt(type.rgbaMasks[0]);
|
||||
//dwGBitMask
|
||||
imageOutput.writeInt(mask[1]);
|
||||
imageOutput.writeInt(type.rgbaMasks[1]);
|
||||
//dwBBitMask
|
||||
imageOutput.writeInt(mask[2]);
|
||||
imageOutput.writeInt(type.rgbaMasks[2]);
|
||||
//dwABitMask
|
||||
imageOutput.writeInt(mask[3]);
|
||||
imageOutput.writeInt(type.rgbaMasks[3]);
|
||||
}
|
||||
else {
|
||||
//write 5 zero integers as fourCC is used
|
||||
@@ -302,7 +291,8 @@ class DDSImageWriter extends ImageWriterBase {
|
||||
imageOutput.writeInt(DDS.PIXEL_FORMAT_FLAG_FOURCC);
|
||||
}
|
||||
else {
|
||||
imageOutput.writeInt(DDS.PIXEL_FORMAT_FLAG_RGB | (type.rgbaMasks != null ? DDS.PIXEL_FORMAT_FLAG_ALPHAPIXELS : 0));
|
||||
imageOutput.writeInt(DDS.PIXEL_FORMAT_FLAG_RGB
|
||||
| (type.rgbaMasks != null && type.rgbaMasks[3] != 0 ? DDS.PIXEL_FORMAT_FLAG_ALPHAPIXELS : 0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,6 +324,7 @@ class DDSImageWriter extends ImageWriterBase {
|
||||
if (args.length != 1) {
|
||||
throw new IllegalArgumentException("Use 1 input file at a time.");
|
||||
}
|
||||
|
||||
ImageIO.write(ImageIO.read(new File(args[0])), "dds", new MemoryCacheImageOutputStream(Files.newOutputStream(Paths.get("output.dds"))));
|
||||
}
|
||||
}
|
||||
|
||||
+8
-19
@@ -33,6 +33,7 @@ package com.twelvemonkeys.imageio.plugins.icns;
|
||||
import com.twelvemonkeys.imageio.ImageWriterBase;
|
||||
import com.twelvemonkeys.imageio.stream.SubImageOutputStream;
|
||||
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
||||
import com.twelvemonkeys.imageio.util.SequenceSupport;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.IIOImage;
|
||||
@@ -55,7 +56,7 @@ import java.util.Iterator;
|
||||
*/
|
||||
public final class ICNSImageWriter extends ImageWriterBase {
|
||||
|
||||
private int sequenceIndex = -1;
|
||||
private final SequenceSupport sequence = new SequenceSupport();
|
||||
private ImageWriter pngDelegate;
|
||||
|
||||
ICNSImageWriter(ImageWriterSpi provider) {
|
||||
@@ -64,7 +65,7 @@ public final class ICNSImageWriter extends ImageWriterBase {
|
||||
|
||||
@Override
|
||||
protected void resetMembers() {
|
||||
sequenceIndex = -1;
|
||||
sequence.reset();
|
||||
|
||||
if (pngDelegate != null) {
|
||||
pngDelegate.dispose();
|
||||
@@ -97,41 +98,29 @@ public final class ICNSImageWriter extends ImageWriterBase {
|
||||
@Override
|
||||
public void prepareWriteSequence(final IIOMetadata streamMetadata) throws IOException {
|
||||
assertOutput();
|
||||
sequence.start();
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
@Override
|
||||
public void endWriteSequence() throws IOException {
|
||||
assertOutput();
|
||||
|
||||
if (sequenceIndex < 0) {
|
||||
throw new IllegalStateException("prepareWriteSequence not called");
|
||||
}
|
||||
sequence.end();
|
||||
|
||||
// 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");
|
||||
}
|
||||
int imageIndex = sequence.advance();
|
||||
|
||||
if (image.hasRaster()) {
|
||||
throw new UnsupportedOperationException("image has a Raster");
|
||||
@@ -148,7 +137,7 @@ public final class ICNSImageWriter extends ImageWriterBase {
|
||||
imageOutput.writeInt(IconResource.typeFromImage(image.getRenderedImage(), "PNG"));
|
||||
imageOutput.writeInt(0); // Size, update later
|
||||
|
||||
processImageStarted(sequenceIndex);
|
||||
processImageStarted(imageIndex);
|
||||
|
||||
// Write icon in PNG format
|
||||
ImageWriter writer = getPNGDelegate();
|
||||
@@ -208,7 +197,7 @@ public final class ICNSImageWriter extends ImageWriterBase {
|
||||
pngDelegate.addIIOWriteWarningListener(new IIOWriteWarningListener() {
|
||||
@Override
|
||||
public void warningOccurred(ImageWriter source, int imageIndex, String warning) {
|
||||
processWarningOccurred(sequenceIndex, warning);
|
||||
processWarningOccurred(sequence.current(), warning);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+9
-23
@@ -42,6 +42,7 @@ import com.twelvemonkeys.imageio.stream.SubImageOutputStream;
|
||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
|
||||
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
||||
import com.twelvemonkeys.imageio.util.SequenceSupport;
|
||||
import com.twelvemonkeys.io.enc.EncoderStream;
|
||||
import com.twelvemonkeys.io.enc.PackBitsEncoder;
|
||||
import com.twelvemonkeys.lang.Validate;
|
||||
@@ -110,12 +111,7 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
||||
// Support storing multiple images in one stream (multi-page TIFF)
|
||||
// Support more of the ImageIO metadata (ie. compression from metadata, etc)
|
||||
|
||||
/**
|
||||
* Flag for active sequence writing
|
||||
*/
|
||||
private boolean writingSequence = false;
|
||||
|
||||
private int sequenceIndex = 0;
|
||||
private final SequenceSupport sequence = new SequenceSupport();
|
||||
|
||||
/**
|
||||
* Metadata writer for sequence writing
|
||||
@@ -751,7 +747,7 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
||||
ifd = ((TIFFImageMetadata) inData).getIFD();
|
||||
}
|
||||
else {
|
||||
TIFFImageMetadata outData = new TIFFImageMetadata(Collections.<Entry>emptySet());
|
||||
TIFFImageMetadata outData = new TIFFImageMetadata(Collections.emptySet());
|
||||
|
||||
try {
|
||||
if (Arrays.asList(inData.getMetadataFormatNames()).contains(SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME)) {
|
||||
@@ -766,7 +762,7 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
||||
}
|
||||
}
|
||||
catch (IIOInvalidTreeException e) {
|
||||
processWarningOccurred(sequenceIndex, "Could not convert image meta data: " + e.getMessage());
|
||||
processWarningOccurred(sequence.current(), "Could not convert image meta data: " + e.getMessage());
|
||||
}
|
||||
|
||||
ifd = outData.getIFD();
|
||||
@@ -966,14 +962,11 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
||||
|
||||
@Override
|
||||
public void prepareWriteSequence(final IIOMetadata streamMetadata) throws IOException {
|
||||
if (writingSequence) {
|
||||
throw new IllegalStateException("sequence writing has already been started!");
|
||||
}
|
||||
sequence.start();
|
||||
|
||||
assertOutput();
|
||||
configureStreamByteOrder(streamMetadata, imageOutput);
|
||||
|
||||
writingSequence = true;
|
||||
sequenceTIFFWriter = new TIFFWriter(isBigTIFF() ? 8 : 4);
|
||||
sequenceTIFFWriter.writeTIFFHeader(imageOutput);
|
||||
sequenceLastIFDPos = imageOutput.getStreamPosition();
|
||||
@@ -985,26 +978,20 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
||||
|
||||
@Override
|
||||
public void writeToSequence(final IIOImage image, final ImageWriteParam param) throws IOException {
|
||||
if (!writingSequence) {
|
||||
throw new IllegalStateException("prepareWriteSequence() must be called before writeToSequence()!");
|
||||
}
|
||||
int sequenceIndex = sequence.advance();
|
||||
|
||||
if (sequenceIndex > 0) {
|
||||
imageOutput.flushBefore(sequenceLastIFDPos);
|
||||
imageOutput.seek(imageOutput.length());
|
||||
}
|
||||
|
||||
sequenceLastIFDPos = writePage(sequenceIndex++, image, param, sequenceTIFFWriter, sequenceLastIFDPos);
|
||||
sequenceLastIFDPos = writePage(sequenceIndex, image, param, sequenceTIFFWriter, sequenceLastIFDPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endWriteSequence() throws IOException {
|
||||
if (!writingSequence) {
|
||||
throw new IllegalStateException("prepareWriteSequence() must be called before endWriteSequence()!");
|
||||
}
|
||||
sequence.end();
|
||||
|
||||
writingSequence = false;
|
||||
sequenceIndex = 0;
|
||||
sequenceTIFFWriter = null;
|
||||
sequenceLastIFDPos = -1;
|
||||
imageOutput.flush();
|
||||
@@ -1014,8 +1001,7 @@ public final class TIFFImageWriter extends ImageWriterBase {
|
||||
protected void resetMembers() {
|
||||
super.resetMembers();
|
||||
|
||||
writingSequence = false;
|
||||
sequenceIndex = 0;
|
||||
sequence.reset();
|
||||
sequenceTIFFWriter = null;
|
||||
sequenceLastIFDPos = -1;
|
||||
}
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<junit.jupiter.version>5.14.3</junit.jupiter.version>
|
||||
<junit.jupiter.version>5.14.4</junit.jupiter.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -191,7 +191,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>3.4.0</version>
|
||||
<version>3.5.0</version>
|
||||
<configuration>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
|
||||
+2
-2
@@ -15,7 +15,7 @@
|
||||
</description>
|
||||
|
||||
<properties>
|
||||
<junit.jupiter.version>5.14.3</junit.jupiter.version>
|
||||
<junit.jupiter.version>5.14.4</junit.jupiter.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -82,7 +82,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.6.1</version>
|
||||
<version>3.6.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>jakarta</id>
|
||||
|
||||
Reference in New Issue
Block a user