Use imageIndex to calculate height/width and buffer offset.

This commit is contained in:
Paul Allen
2024-09-24 17:49:58 +01:00
parent edf132b738
commit 05f754f6e5
3 changed files with 52 additions and 51 deletions
@@ -2,18 +2,18 @@ package com.twelvemonkeys.imageio.plugins.dds;
import javax.imageio.IIOException; import javax.imageio.IIOException;
import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.ImageInputStream;
import java.awt.Dimension;
import java.io.IOException; import java.io.IOException;
import java.math.BigInteger; import java.math.BigInteger;
import java.nio.ByteOrder;
import java.util.Arrays; import java.util.Arrays;
final class DDSHeader { final class DDSHeader {
// https://learn.microsoft.com/en-us/windows/win32/direct3ddds/dx-graphics-dds-pguide // https://learn.microsoft.com/en-us/windows/win32/direct3ddds/dx-graphics-dds-pguide
private int flags; private int flags;
private int width;
private int height; private int mipMapCount;
private int mipmap; private Dimension[] dimensions;
private int pixelFormatFlags; private int pixelFormatFlags;
private int fourCC; private int fourCC;
@@ -25,7 +25,7 @@ final class DDSHeader {
public static DDSHeader read(final ImageInputStream imageInput) throws IOException { public static DDSHeader read(final ImageInputStream imageInput) throws IOException {
DDSHeader header = new DDSHeader(); DDSHeader header = new DDSHeader();
// Read MAGIC bytes [0,3] // Read MAGIC bytes [0,3]
byte[] magic = new byte[DDS.MAGIC.length]; byte[] magic = new byte[DDS.MAGIC.length];
imageInput.readFully(magic); imageInput.readFully(magic);
@@ -50,13 +50,15 @@ final class DDSHeader {
} }
// Read Height & Width // Read Height & Width
header.height = imageInput.readInt(); // [12,15] int dwHeight = imageInput.readInt(); // [12,15]
header.width = imageInput.readInt(); // [16,19] int dwWidth = imageInput.readInt(); // [16,19]
int dwPitchOrLinearSize = imageInput.readInt(); // [20,23] int dwPitchOrLinearSize = imageInput.readInt(); // [20,23]
int dwDepth = imageInput.readInt(); // [24,27] int dwDepth = imageInput.readInt(); // [24,27]
header.mipmap = imageInput.readInt(); // [28,31] header.mipMapCount = imageInput.readInt(); // [28,31]
// build dimensions list
header.addDimensions(dwWidth, dwHeight);
byte[] dwReserved1 = new byte[11 * 4]; // [32,75] byte[] dwReserved1 = new byte[11 * 4]; // [32,75]
imageInput.readFully(dwReserved1); imageInput.readFully(dwReserved1);
@@ -82,28 +84,35 @@ final class DDSHeader {
return header; return header;
} }
private void addDimensions(int width, int height) {
dimensions = new Dimension[getMipMapCount()];
int w = width;
int h = height;
for (int i = 0; i < getMipMapCount(); i++) {
dimensions[i] = new Dimension(w, h);
w /= 2;
h /= 2;
}
}
private boolean getFlag(int mask) { private boolean getFlag(int mask) {
return (flags & mask) != 0; return (flags & mask) != 0;
} }
public int getWidth() { public int getWidth(int imageIndex) {
return width; int lim = dimensions[imageIndex].width;
return (lim <= 0) ? 1 : lim;
} }
public void setWidth(int width) { public int getHeight(int imageIndex) {
this.width = width; int lim = dimensions[imageIndex].height;
return (lim <= 0) ? 1 : lim;
} }
public int getHeight() { public int getMipMapCount() {
return height; // 0 = (unused) or 1 = (1 level), but still only one 'base' image
} return (mipMapCount == 0) ? 1 : mipMapCount;
public void setHeight(int height) {
this.height = height;
}
public int getMipmap() {
return mipmap;
} }
public int getAlphaMask() { public int getAlphaMask() {
@@ -34,7 +34,7 @@ public final class DDSImageReader extends ImageReaderBase {
checkBounds(imageIndex); checkBounds(imageIndex);
readHeader(); readHeader();
return header.getWidth(); return header.getWidth(imageIndex);
} }
@Override @Override
@@ -42,7 +42,14 @@ public final class DDSImageReader extends ImageReaderBase {
checkBounds(imageIndex); checkBounds(imageIndex);
readHeader(); readHeader();
return header.getHeight(); return header.getHeight(imageIndex);
}
@Override
public int getNumImages(final boolean allowSearch) throws IOException {
readHeader();
return header.getMipMapCount();
} }
@Override @Override
@@ -29,39 +29,21 @@ final class DDSReader {
this.header = header; this.header = header;
} }
public int[] read(ImageInputStream imageInput, int mipmapLevel) throws IOException { public int[] read(ImageInputStream imageInput, int imageIndex) throws IOException {
// header
int width = header.getWidth();
int height = header.getHeight();
int mipmap = header.getMipmap();
if (mipmapLevel > mipmap) {
throw new IIOException("Invalid mipmap level: " + mipmapLevel);
}
// type // type
DDSType type = getType(); DDSType type = getType();
// length // offset buffer to index mipmap image
int len = getLength(type, width, height); byte[] buffer = null;
byte[] buffer = new byte[len]; for (int i = 0; i <= imageIndex; i++) {
imageInput.readFully(buffer); int len = getLength(type, i);
for (int i = 1; i < mipmapLevel; i++) {
width /= 2;
height /= 2;
// length
len = getLength(type, width, height);
buffer = new byte[len]; buffer = new byte[len];
imageInput.readFully(buffer); imageInput.readFully(buffer);
} }
if (width <= 0) width = 1;
if (height <= 0) height = 1;
header.setWidth(width); int width = header.getWidth(imageIndex);
header.setHeight(height); int height = header.getHeight(imageIndex);
switch (type) { switch (type) {
case DXT1: case DXT1:
@@ -163,7 +145,10 @@ final class DDSReader {
} }
} }
private static int getLength(DDSType type, int width, int height) throws IIOException { private int getLength(DDSType type, int imageIndex) throws IIOException {
int width = header.getWidth(imageIndex);
int height = header.getHeight(imageIndex);
switch (type) { switch (type) {
case DXT1: case DXT1:
return 8 * ((width + 3) / 4) * ((height + 3) / 4); return 8 * ((width + 3) / 4) * ((height + 3) / 4);