SvgImageReaderSpi.java
package pro.verron.officestamper.imageio.svg;
import javax.imageio.ImageReader;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.stream.ImageInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/// Minimal ImageIO SPI for SVG.
///
/// Detects an SVG if the stream prefix contains a `<svg` root element (case-insensitive),
/// allowing optional XML declarations and whitespace.
public final class SvgImageReaderSpi
extends ImageReaderSpi {
private static final String[] NAMES = {"svg"};
private static final String[] SUFFIXES = {"svg"};
private static final String[] MIMES = {"image/svg+xml"};
public SvgImageReaderSpi() {
super("Office-stamper",
"3.3",
NAMES,
SUFFIXES,
MIMES,
SvgImageReader.class.getName(),
new Class[]{ImageInputStream.class},
null,
false,
null,
null,
null,
null,
false,
null,
null,
null,
null);
}
@Override
public boolean canDecodeInput(Object source) {
if (!(source instanceof ImageInputStream iis)) return false;
long pos;
try {
pos = iis.getStreamPosition();
byte[] buf = new byte[2048];
int n = iis.read(buf);
iis.seek(pos);
if (n <= 0) return false;
String s = new String(buf, 0, n, StandardCharsets.UTF_8).toLowerCase();
// Skip XML declaration if any and test presence of <svg
int idx = s.indexOf("<svg");
if (idx >= 0) return true;
// Some files may declare namespace prefix: <svg:svg ...>
return s.contains("<svg:svg");
} catch (IOException e) {
try {iis.seek(0);} catch (IOException ignore) {}
return false;
}
}
@Override
public ImageReader createReaderInstance(Object extension) {
return new SvgImageReader(this);
}
@Override
public String getDescription(java.util.Locale locale) {
return "Minimal SVG metadata reader (width/height via attributes or viewBox); no rasterization";
}
}