mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2026-03-17 00:00:06 -04:00
Using new sequence support in DDSImageWriter
+ some minor bonus clean-up
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -77,5 +77,4 @@ final class DDSImageMetadata extends StandardImageMetadataSupport {
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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"))));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user