WarpPI/desktop/src/main/java/ar/com/hjg/pngj/IDatChunkWriter.java

134 lines
3.0 KiB
Java

package ar.com.hjg.pngj;
import java.io.OutputStream;
import ar.com.hjg.pngj.chunks.ChunkHelper;
import ar.com.hjg.pngj.chunks.ChunkRaw;
/**
* Outputs a sequence of IDAT-like chunk, that is filled progressively until the
* max chunk length is reached (or until
* flush())
*/
public class IDatChunkWriter {
private static final int MAX_LEN_DEFAULT = 32768; // 32K rather arbitrary - data only
private final OutputStream outputStream;
private final int maxChunkLen;
private byte[] buf;
private int offset = 0;
private int availLen;
private long totalBytesWriten = 0; // including header+crc
private int chunksWriten = 0;
public IDatChunkWriter(OutputStream outputStream) {
this(outputStream, 0);
}
public IDatChunkWriter(OutputStream outputStream, int maxChunkLength) {
this.outputStream = outputStream;
this.maxChunkLen = maxChunkLength > 0 ? maxChunkLength : MAX_LEN_DEFAULT;
buf = new byte[maxChunkLen];
availLen = maxChunkLen - offset;
postReset();
}
public IDatChunkWriter(OutputStream outputStream, byte[] b) {
this.outputStream = outputStream;
this.buf = b != null ? b : new byte[MAX_LEN_DEFAULT];
this.maxChunkLen = b.length;
availLen = maxChunkLen - offset;
postReset();
}
protected byte[] getChunkId() {
return ChunkHelper.b_IDAT;
}
/**
* Writes a chhunk if there is more than minLenToWrite.
*
* This is normally called internally, but can be called explicitly to force
* flush.
*/
public final void flush() {
if (offset > 0 && offset >= minLenToWrite()) {
ChunkRaw c = new ChunkRaw(offset, getChunkId(), false);
c.data = buf;
c.writeChunk(outputStream);
totalBytesWriten += c.len + 12;
chunksWriten++;
offset = 0;
availLen = maxChunkLen;
postReset();
}
}
public int getOffset() {
return offset;
}
public int getAvailLen() {
return availLen;
}
/** triggers an flush+reset if appropiate */
public void incrementOffset(int n) {
offset += n;
availLen -= n;
if (availLen < 0)
throw new PngjOutputException("Anomalous situation");
if (availLen == 0) {
flush();
}
}
/**
* this should rarely be used, the normal way (to avoid double copying) is
* to get the buffer and write directly to it
*/
public void write(byte[] b, int o, int len) {
while (len > 0) {
int n = len <= availLen ? len : availLen;
System.arraycopy(b, o, buf, offset, n);
incrementOffset(n);
len -= n;
o += n;
}
}
/** this will be called after reset */
protected void postReset() {
// fdat could override this (and minLenToWrite) to add a prefix
}
protected int minLenToWrite() {
return 1;
}
public void close() {
flush();
offset = 0;
buf = null;
}
/**
* You can write directly to this buffer, using {@link #getOffset()} and
* {@link #getAvailLen()}. You should call
* {@link #incrementOffset(int)} inmediately after.
*/
public byte[] getBuf() {
return buf;
}
public long getTotalBytesWriten() {
return totalBytesWriten;
}
public int getChunksWriten() {
return chunksWriten;
}
}