package com.bumptech.glide.load.data;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Adds an exif segment with an orientation attribute to a wrapped {@link InputStream} containing
* image data.
*
* <p>This class assumes that the wrapped stream contains an image format that can contain
* exif information and performs no verification. </p>
*/
public final class ExifOrientationStream extends FilterInputStream {
/** Allow two bytes for the file format. */
private static final int SEGMENT_START_POSITION = 2;
private static final byte[] EXIF_SEGMENT = new byte[] {
/** segment start id. */
(byte) 0xFF,
/** segment type. */
(byte) 0xE1,
/** segmentLength. */
0x00,
(byte) 0x1C,
/** exif identifier. */
0x45,
0x78,
0x69,
0x66,
0x00,
0x00,
/** motorola byte order (big endian). */
(byte) 0x4D,
(byte) 0x4D,
/** filler? */
0x00,
0x00,
/** first id offset. */
0x00,
0x00,
0x00,
0x08,
/** tagCount. */
0x00,
0x01,
/** exif tag type. */
0x01,
0x12,
/** 2 byte format. */
0x00,
0x02,
/** component count. */
0x00,
0x00,
0x00,
0x01,
/** 2 byte orientation value, the first byte of which is always 0. */
0x00,
};
private static final int SEGMENT_LENGTH = EXIF_SEGMENT.length;
private static final int ORIENTATION_POSITION = SEGMENT_LENGTH + SEGMENT_START_POSITION;
private final byte orientation;
private int position;
public ExifOrientationStream(InputStream in, int orientation) {
super(in);
if (orientation < -1 || orientation > 8) {
throw new IllegalArgumentException("Cannot add invalid orientation: " + orientation);
}
this.orientation = (byte) orientation;
}
@Override
public boolean markSupported() {
return false;
}
@Override
public void mark(int readlimit) {
throw new UnsupportedOperationException();
}
@Override
public int read() throws IOException {
final int result;
if (position < SEGMENT_START_POSITION || position > ORIENTATION_POSITION) {
result = super.read();
} else if (position == ORIENTATION_POSITION) {
result = orientation;
} else {
result = EXIF_SEGMENT[position - SEGMENT_START_POSITION] & 0xFF;
}
if (result != -1) {
position++;
}
return result;
}
@Override
public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
int read;
if (position > ORIENTATION_POSITION) {
read = super.read(buffer, byteOffset, byteCount);
} else if (position == ORIENTATION_POSITION) {
buffer[byteOffset] = orientation;
read = 1;
} else if (position < SEGMENT_START_POSITION) {
read = super.read(buffer, byteOffset, SEGMENT_START_POSITION - position);
} else {
read = Math.min(ORIENTATION_POSITION - position, byteCount);
System.arraycopy(EXIF_SEGMENT, position - SEGMENT_START_POSITION, buffer, byteOffset, read);
}
if (read > 0) {
position += read;
}
return read;
}
@Override
public long skip(long byteCount) throws IOException {
long skipped = super.skip(byteCount);
if (skipped > 0) {
position += skipped;
}
return skipped;
}
@Override
public void reset() throws IOException {
throw new UnsupportedOperationException();
}
}