WarpPI/desktop/src/main/java/ar/com/hjg/pngj/chunks/ChunksList.java

171 lines
4.8 KiB
Java

package ar.com.hjg.pngj.chunks;
import java.util.ArrayList;
import java.util.List;
import ar.com.hjg.pngj.ImageInfo;
import ar.com.hjg.pngj.PngjException;
/**
* All chunks that form an image, read or to be written.
* <p>
* chunks include all chunks, but IDAT is a single pseudo chunk without data
**/
public class ChunksList {
// ref: http://www.w3.org/TR/PNG/#table53
public static final int CHUNK_GROUP_0_IDHR = 0; // required - single
public static final int CHUNK_GROUP_1_AFTERIDHR = 1; // optional - multiple
public static final int CHUNK_GROUP_2_PLTE = 2; // optional - single
public static final int CHUNK_GROUP_3_AFTERPLTE = 3; // optional - multple
public static final int CHUNK_GROUP_4_IDAT = 4; // required (single pseudo chunk)
public static final int CHUNK_GROUP_5_AFTERIDAT = 5; // optional - multple
public static final int CHUNK_GROUP_6_END = 6; // only 1 chunk - requried
/**
* All chunks, read (or written)
*
* But IDAT is a single pseudo chunk without data
*/
List<PngChunk> chunks = new ArrayList<PngChunk>();
// protected HashMap<String, List<PngChunk>> chunksById = new HashMap<String, List<PngChunk>>();
// // does not include IDAT
final ImageInfo imageInfo; // only required for writing
boolean withPlte = false;
public ChunksList(ImageInfo imfinfo) {
this.imageInfo = imfinfo;
}
/**
* WARNING: this does NOT return a copy, but the list itself. The called
* should not modify this directly! Don't use
* this to manipulate the chunks.
*/
public List<PngChunk> getChunks() {
return chunks;
}
protected static List<PngChunk> getXById(final List<PngChunk> list, final String id, final String innerid) {
if (innerid == null)
return ChunkHelper.filterList(list, new ChunkPredicate() {
public boolean match(PngChunk c) {
return c.id.equals(id);
}
});
else
return ChunkHelper.filterList(list, new ChunkPredicate() {
public boolean match(PngChunk c) {
if (!c.id.equals(id))
return false;
if (c instanceof PngChunkTextVar && !((PngChunkTextVar) c).getKey().equals(innerid))
return false;
if (c instanceof PngChunkSPLT && !((PngChunkSPLT) c).getPalName().equals(innerid))
return false;
return true;
}
});
}
/**
* Adds chunk in next position. This is used onyl by the pngReader
*/
public void appendReadChunk(PngChunk chunk, int chunkGroup) {
chunk.setChunkGroup(chunkGroup);
chunks.add(chunk);
if (chunk.id.equals(PngChunkPLTE.ID))
withPlte = true;
}
/**
* All chunks with this ID
*
* @param id
* @return List, empty if none
*/
public List<? extends PngChunk> getById(final String id) {
return getById(id, null);
}
/**
* If innerid!=null and the chunk is PngChunkTextVar or PngChunkSPLT, it's
* filtered by that id
*
* @param id
* @return innerid Only used for text and SPLT chunks
* @return List, empty if none
*/
public List<? extends PngChunk> getById(final String id, final String innerid) {
return getXById(chunks, id, innerid);
}
/**
* Returns only one chunk
*
* @param id
* @return First chunk found, null if not found
*/
public PngChunk getById1(final String id) {
return getById1(id, false);
}
/**
* Returns only one chunk or null if nothing found - does not include queued
* <p>
* If more than one chunk is found, then an exception is thrown
* (failifMultiple=true or chunk is single) or the last
* one is returned (failifMultiple=false)
**/
public PngChunk getById1(final String id, final boolean failIfMultiple) {
return getById1(id, null, failIfMultiple);
}
/**
* Returns only one chunk or null if nothing found - does not include queued
* <p>
* If more than one chunk (after filtering by inner id) is found, then an
* exception is thrown (failifMultiple=true or
* chunk is single) or the last one is returned (failifMultiple=false)
**/
public PngChunk getById1(final String id, final String innerid, final boolean failIfMultiple) {
List<? extends PngChunk> list = getById(id, innerid);
if (list.isEmpty())
return null;
if (list.size() > 1 && (failIfMultiple || !list.get(0).allowsMultiple()))
throw new PngjException("unexpected multiple chunks id=" + id);
return list.get(list.size() - 1);
}
/**
* Finds all chunks "equivalent" to this one
*
* @param c2
* @return Empty if nothing found
*/
public List<PngChunk> getEquivalent(final PngChunk c2) {
return ChunkHelper.filterList(chunks, new ChunkPredicate() {
public boolean match(PngChunk c) {
return ChunkHelper.equivalent(c, c2);
}
});
}
public String toString() {
return "ChunkList: read: " + chunks.size();
}
/**
* for debugging
*/
public String toStringFull() {
StringBuilder sb = new StringBuilder(toString());
sb.append("\n Read:\n");
for (PngChunk chunk : chunks) {
sb.append(chunk).append(" G=" + chunk.getChunkGroup() + "\n");
}
return sb.toString();
}
}