mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-04 20:15:28 -04:00
Added JPEG utils.
This commit is contained in:
parent
8d5b775851
commit
4d9661f950
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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 "TwelveMonkeys" 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 OWNER 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.metadata.jpeg;
|
||||
|
||||
/**
|
||||
* JPEG
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: JPEG.java,v 1.0 11.02.11 15.51 haraldk Exp$
|
||||
*/
|
||||
public interface JPEG {
|
||||
int SOS = 0xFFDA;
|
||||
int SOI = 0xFFD8;
|
||||
int EOI = 0xFFD9;
|
||||
|
||||
int APP0 = 0xFFE0;
|
||||
int APP1 = 0xFFE1;
|
||||
int APP2 = 0xFFE2;
|
||||
int APP14 = 0xFFEE;
|
||||
|
||||
int SOF0 = 0xFFC0;
|
||||
int SOF1 = 0xFFC1;
|
||||
int SOF2 = 0xFFC2;
|
||||
int SOF3 = 0xFFC3;
|
||||
int SOF5 = 0xFFC5;
|
||||
int SOF6 = 0xFFC6;
|
||||
int SOF7 = 0xFFC7;
|
||||
int SOF9 = 0xFFC9;
|
||||
int SOF10 = 0xFFCA;
|
||||
int SOF11 = 0xFFCB;
|
||||
int SOF13 = 0xFFCD;
|
||||
int SOF14 = 0xFFCE;
|
||||
int SOF15 = 0xFFCF;
|
||||
}
|
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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 "TwelveMonkeys" 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 OWNER 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.metadata.jpeg;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.io.*;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* JPEGSegmentUtil
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: JPEGSegmentUtil.java,v 1.0 24.01.11 17.37 haraldk Exp$
|
||||
*/
|
||||
public final class JPEGSegmentUtil {
|
||||
public static final Map<Integer, List<String>> ALL_SEGMENTS = Collections.emptyMap();
|
||||
|
||||
private JPEGSegmentUtil() {}
|
||||
|
||||
// TODO: Allow for multiple images (multiple SOI markers), using specified index?
|
||||
public static List<Segment> readSegments(final ImageInputStream stream, final int appMarker, final String segmentName) throws IOException {
|
||||
return readSegments(stream, Collections.singletonMap(appMarker, Collections.singletonList(segmentName)));
|
||||
}
|
||||
|
||||
public static List<Segment> readSegments(final ImageInputStream stream, Map<Integer, List<String>> segmentIdentifiers) throws IOException {
|
||||
readSOI(stream);
|
||||
|
||||
List<Segment> segments = Collections.emptyList();
|
||||
|
||||
Segment segment;
|
||||
try {
|
||||
while (!isImageDone(segment = readSegment(stream, segmentIdentifiers))) {
|
||||
// while (!isImageDone(segment = readSegment(stream, ALL_SEGMENTS))) {
|
||||
// System.err.println("segment: " + segment);
|
||||
|
||||
if (isRequested(segment, segmentIdentifiers)) {
|
||||
if (segments == Collections.EMPTY_LIST) {
|
||||
segments = new ArrayList<Segment>();
|
||||
}
|
||||
|
||||
segments.add(segment);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (EOFException ignore) {
|
||||
// Just end here, in case of malformed stream
|
||||
}
|
||||
|
||||
return segments;
|
||||
}
|
||||
|
||||
private static boolean isRequested(Segment segment, Map<Integer, List<String>> segmentIdentifiers) {
|
||||
return segmentIdentifiers == ALL_SEGMENTS ||
|
||||
(segmentIdentifiers.containsKey(segment.marker) &&
|
||||
(segment.identifier() == null && segmentIdentifiers.get(segment.marker) == null || containsSafe(segment, segmentIdentifiers)));
|
||||
}
|
||||
|
||||
private static boolean containsSafe(Segment segment, Map<Integer, List<String>> segmentIdentifiers) {
|
||||
List<String> identifiers = segmentIdentifiers.get(segment.marker);
|
||||
return identifiers != null && identifiers.contains(segment.identifier());
|
||||
}
|
||||
|
||||
private static boolean isImageDone(final Segment segment) {
|
||||
// We're done with this image if we encounter a SOS, EOI (or a new SOI, but that should never happen)
|
||||
return segment.marker == JPEG.SOS || segment.marker == JPEG.EOI || segment.marker == JPEG.SOI;
|
||||
}
|
||||
|
||||
static String asNullTerminatedAsciiString(final byte[] data, final int offset) {
|
||||
for (int i = 0; i < data.length - offset; i++) {
|
||||
if (data[i] == 0 || i > 255) {
|
||||
return asAsciiString(data, offset, offset + i);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static String asAsciiString(final byte[] data, final int offset, final int length) {
|
||||
return new String(data, offset, length, Charset.forName("ascii"));
|
||||
}
|
||||
|
||||
static void readSOI(final ImageInputStream stream) throws IOException {
|
||||
if (stream.readUnsignedShort() != JPEG.SOI) {
|
||||
throw new IIOException("Not a JPEG stream");
|
||||
}
|
||||
}
|
||||
|
||||
static Segment readSegment(final ImageInputStream stream, Map<Integer, List<String>> segmentIdentifiers) throws IOException {
|
||||
int marker = stream.readUnsignedShort();
|
||||
int length = stream.readUnsignedShort(); // Length including length field itself
|
||||
|
||||
byte[] data;
|
||||
|
||||
if (segmentIdentifiers == ALL_SEGMENTS || segmentIdentifiers.containsKey(marker)) {
|
||||
data = new byte[length - 2];
|
||||
stream.readFully(data);
|
||||
}
|
||||
else {
|
||||
data = null;
|
||||
stream.skipBytes(length - 2);
|
||||
}
|
||||
|
||||
return new Segment(marker, data);
|
||||
}
|
||||
|
||||
public static final class Segment {
|
||||
private final int marker;
|
||||
private final byte[] data;
|
||||
private String id;
|
||||
|
||||
Segment(int marker, byte[] data) {
|
||||
this.marker = marker;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
int segmentLength() {
|
||||
// This is the length field as read from the stream
|
||||
return data.length + 2;
|
||||
}
|
||||
|
||||
public int marker() {
|
||||
return marker;
|
||||
}
|
||||
|
||||
public String identifier() {
|
||||
if (id == null) {
|
||||
if (marker >= 0xFFE0 && marker <= 0xFFEF) {
|
||||
// Only for APPn markers
|
||||
id = asNullTerminatedAsciiString(data, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
public InputStream data() {
|
||||
return new ByteArrayInputStream(data, offset(), length());
|
||||
}
|
||||
|
||||
public int length() {
|
||||
return data.length - offset();
|
||||
}
|
||||
|
||||
private int offset() {
|
||||
String identifier = identifier();
|
||||
return identifier == null ? 0 : identifier.length() + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("Segment[%04x/%s size: %d]", marker, identifier(), segmentLength());
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user