mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2026-04-30 00:00:01 -04:00
Major ImageMetadata refactor for more consistent standard metadata support.
Fixes a few related bugs as a bonus.
This commit is contained in:
+2
-5
@@ -43,7 +43,7 @@ import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.awt.*;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.color.*;
|
||||
import java.awt.image.*;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataInputStream;
|
||||
@@ -468,10 +468,7 @@ public final class PNMImageReader extends ImageReaderBase {
|
||||
|
||||
@Override
|
||||
public IIOMetadata getImageMetadata(final int imageIndex) throws IOException {
|
||||
checkBounds(imageIndex);
|
||||
readHeader();
|
||||
|
||||
return new PNMMetadata(header);
|
||||
return new PNMMetadata(getRawImageType(imageIndex), header);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
|
||||
+38
-116
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Harald Kuhr
|
||||
* Copyright (c) 2022, Harald Kuhr
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -30,92 +30,35 @@
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.pnm;
|
||||
|
||||
import com.twelvemonkeys.imageio.AbstractMetadata;
|
||||
import com.twelvemonkeys.imageio.StandardImageMetadataSupport;
|
||||
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.metadata.IIOMetadataNode;
|
||||
import java.awt.*;
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.awt.image.*;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
final class PNMMetadata extends AbstractMetadata {
|
||||
/**
|
||||
* PNMMetadata.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
*/
|
||||
final class PNMMetadata extends StandardImageMetadataSupport {
|
||||
private final PNMHeader header;
|
||||
|
||||
PNMMetadata(final PNMHeader header) {
|
||||
PNMMetadata(ImageTypeSpecifier type, PNMHeader header) {
|
||||
super(builder(type)
|
||||
.withColorSpaceType(colorSpace(header))
|
||||
// TODO: Might make sense to set gamma?
|
||||
.withBlackIsZero(header.getTupleType() != TupleType.BLACKANDWHITE_WHITE_IS_ZERO)
|
||||
.withSignificantBitsPerSample(significantBits(header))
|
||||
.withSampleMSB(header.getByteOrder() == ByteOrder.BIG_ENDIAN ? 0 : header.getBitsPerSample() - 1)
|
||||
.withOrientation(orientation(header))
|
||||
);
|
||||
|
||||
this.header = header;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IIOMetadataNode getStandardChromaNode() {
|
||||
IIOMetadataNode chroma = new IIOMetadataNode("Chroma");
|
||||
|
||||
IIOMetadataNode csType = new IIOMetadataNode("ColorSpaceType");
|
||||
switch (header.getTupleType()) {
|
||||
case BLACKANDWHITE:
|
||||
case BLACKANDWHITE_ALPHA:
|
||||
case BLACKANDWHITE_WHITE_IS_ZERO:
|
||||
case GRAYSCALE:
|
||||
case GRAYSCALE_ALPHA:
|
||||
csType.setAttribute("name", "GRAY");
|
||||
break;
|
||||
case RGB:
|
||||
case RGB_ALPHA:
|
||||
csType.setAttribute("name", "RGB");
|
||||
break;
|
||||
case CMYK:
|
||||
case CMYK_ALPHA:
|
||||
csType.setAttribute("name", "CMYK");
|
||||
break;
|
||||
}
|
||||
|
||||
if (csType.getAttribute("name") != null) {
|
||||
chroma.appendChild(csType);
|
||||
}
|
||||
|
||||
IIOMetadataNode numChannels = new IIOMetadataNode("NumChannels");
|
||||
numChannels.setAttribute("value", Integer.toString(header.getSamplesPerPixel()));
|
||||
chroma.appendChild(numChannels);
|
||||
|
||||
// TODO: Might make sense to set gamma?
|
||||
|
||||
IIOMetadataNode blackIsZero = new IIOMetadataNode("BlackIsZero");
|
||||
blackIsZero.setAttribute("value", header.getTupleType() == TupleType.BLACKANDWHITE_WHITE_IS_ZERO
|
||||
? "FALSE"
|
||||
: "TRUE");
|
||||
chroma.appendChild(blackIsZero);
|
||||
|
||||
return chroma;
|
||||
}
|
||||
|
||||
// No compression
|
||||
|
||||
@Override
|
||||
protected IIOMetadataNode getStandardDataNode() {
|
||||
IIOMetadataNode node = new IIOMetadataNode("Data");
|
||||
|
||||
IIOMetadataNode sampleFormat = new IIOMetadataNode("SampleFormat");
|
||||
sampleFormat.setAttribute("value", header.getTransferType() == DataBuffer.TYPE_FLOAT
|
||||
? "Real"
|
||||
: "UnsignedIntegral");
|
||||
node.appendChild(sampleFormat);
|
||||
|
||||
IIOMetadataNode bitsPerSample = new IIOMetadataNode("BitsPerSample");
|
||||
bitsPerSample.setAttribute("value", createListValue(header.getSamplesPerPixel(), Integer.toString(header.getBitsPerSample())));
|
||||
node.appendChild(bitsPerSample);
|
||||
|
||||
IIOMetadataNode significantBitsPerSample = new IIOMetadataNode("SignificantBitsPerSample");
|
||||
significantBitsPerSample.setAttribute("value", createListValue(header.getSamplesPerPixel(), Integer.toString(computeSignificantBits())));
|
||||
node.appendChild(significantBitsPerSample);
|
||||
|
||||
String msb = header.getByteOrder() == ByteOrder.BIG_ENDIAN
|
||||
? "0"
|
||||
: Integer.toString(header.getBitsPerSample() - 1);
|
||||
IIOMetadataNode sampleMSB = new IIOMetadataNode("SampleMSB");
|
||||
sampleMSB.setAttribute("value", createListValue(header.getSamplesPerPixel(), msb));
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
private int computeSignificantBits() {
|
||||
private static int significantBits(PNMHeader header) {
|
||||
if (header.getTransferType() == DataBuffer.TYPE_FLOAT) {
|
||||
return header.getBitsPerSample();
|
||||
}
|
||||
@@ -132,38 +75,30 @@ final class PNMMetadata extends AbstractMetadata {
|
||||
return significantBits;
|
||||
}
|
||||
|
||||
private String createListValue(final int itemCount, final String... values) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
if (buffer.length() > 0) {
|
||||
buffer.append(' ');
|
||||
}
|
||||
|
||||
buffer.append(values[i % values.length]);
|
||||
private static ColorSpaceType colorSpace(PNMHeader header) {
|
||||
switch (header.getTupleType()) {
|
||||
case BLACKANDWHITE:
|
||||
case BLACKANDWHITE_ALPHA:
|
||||
case BLACKANDWHITE_WHITE_IS_ZERO:
|
||||
case GRAYSCALE:
|
||||
case GRAYSCALE_ALPHA:
|
||||
return ColorSpaceType.GRAY;
|
||||
default:
|
||||
return null; // Fall back to color model's type
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IIOMetadataNode getStandardDimensionNode() {
|
||||
IIOMetadataNode dimension = new IIOMetadataNode("Dimension");
|
||||
|
||||
IIOMetadataNode imageOrientation = new IIOMetadataNode("ImageOrientation");
|
||||
imageOrientation.setAttribute("value",
|
||||
header.getFileType() == PNM.PFM_GRAY || header.getFileType() == PNM.PFM_RGB
|
||||
? "FlipH"
|
||||
: "Normal");
|
||||
dimension.appendChild(imageOrientation);
|
||||
|
||||
return dimension;
|
||||
private static ImageOrientation orientation(PNMHeader header) {
|
||||
// For some reason, the float values are stored bottom-up
|
||||
return header.getFileType() == PNM.PFM_GRAY || header.getFileType() == PNM.PFM_RGB
|
||||
? ImageOrientation.FlipH
|
||||
: ImageOrientation.Normal;
|
||||
}
|
||||
|
||||
// No document node
|
||||
|
||||
@Override
|
||||
protected IIOMetadataNode getStandardTextNode() {
|
||||
// TODO: Could avoid this override, by changing the StandardImageMetadataSupport to
|
||||
// use List<Entry<String, String>> instead of Map<String, String> (we use duplicate "comment"s).
|
||||
if (!header.getComments().isEmpty()) {
|
||||
IIOMetadataNode text = new IIOMetadataNode("Text");
|
||||
|
||||
@@ -179,17 +114,4 @@ final class PNMMetadata extends AbstractMetadata {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// No tiling
|
||||
|
||||
@Override
|
||||
protected IIOMetadataNode getStandardTransparencyNode() {
|
||||
IIOMetadataNode transparency = new IIOMetadataNode("Transparency");
|
||||
|
||||
IIOMetadataNode alpha = new IIOMetadataNode("Alpha");
|
||||
alpha.setAttribute("value", header.getTransparency() == Transparency.OPAQUE ? "none" : "nonpremultiplied");
|
||||
transparency.appendChild(alpha);
|
||||
|
||||
return transparency;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user