All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jogamp.opengl.util.pngj.chunks.PngChunk Maven / Gradle / Ivy

There is a newer version: 2.3.2
Show newest version
package jogamp.opengl.util.pngj.chunks;

import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;

import jogamp.opengl.util.pngj.ImageInfo;
import jogamp.opengl.util.pngj.PngjExceptionInternal;

/**
 * Represents a instance of a PNG chunk.
 * 

* See http://www.libpng.org/pub/png/spec/1.2/PNG-Chunks * .html *

* Concrete classes should extend {@link PngChunkSingle} or {@link PngChunkMultiple} *

* Note that some methods/fields are type-specific (getOrderingConstraint(), allowsMultiple()),
* some are 'almost' type-specific (id,crit,pub,safe; the exception is PngUKNOWN),
* and the rest are instance-specific */ public abstract class PngChunk { /** * Chunk-id: 4 letters */ public final String id; /** * Autocomputed at creation time */ public final boolean crit, pub, safe; protected final ImageInfo imgInfo; /** * Possible ordering constraint for a PngChunk type -only relevant for ancillary chunks. Theoretically, there could * be more general constraints, but these cover the constraints for standard chunks. */ public enum ChunkOrderingConstraint { /** * no ordering constraint */ NONE, /** * Must go before PLTE (and hence, also before IDAT) */ BEFORE_PLTE_AND_IDAT, /** * Must go after PLTE but before IDAT */ AFTER_PLTE_BEFORE_IDAT, /** * Must before IDAT (before or after PLTE) */ BEFORE_IDAT, /** * Does not apply */ NA; public boolean mustGoBeforePLTE() { return this == BEFORE_PLTE_AND_IDAT; } public boolean mustGoBeforeIDAT() { return this == BEFORE_IDAT || this == BEFORE_PLTE_AND_IDAT || this == AFTER_PLTE_BEFORE_IDAT; } public boolean mustGoAfterPLTE() { return this == AFTER_PLTE_BEFORE_IDAT; } } private boolean priority = false; // For writing. Queued chunks with high priority will be written as soon as // possible protected int chunkGroup = -1; // chunk group where it was read or writen protected int length = -1; // merely informational, for read chunks protected long offset = 0; // merely informational, for read chunks /** * This static map defines which PngChunk class correspond to which ChunkID *

* The client can add other chunks to this map statically, before reading an image, calling * PngChunk.factoryRegister(id,class) */ private final static Map> factoryMap = new HashMap>(); static { factoryMap.put(ChunkHelper.IDAT, PngChunkIDAT.class); factoryMap.put(ChunkHelper.IHDR, PngChunkIHDR.class); factoryMap.put(ChunkHelper.PLTE, PngChunkPLTE.class); factoryMap.put(ChunkHelper.IEND, PngChunkIEND.class); factoryMap.put(ChunkHelper.tEXt, PngChunkTEXT.class); factoryMap.put(ChunkHelper.iTXt, PngChunkITXT.class); factoryMap.put(ChunkHelper.zTXt, PngChunkZTXT.class); factoryMap.put(ChunkHelper.bKGD, PngChunkBKGD.class); factoryMap.put(ChunkHelper.gAMA, PngChunkGAMA.class); factoryMap.put(ChunkHelper.pHYs, PngChunkPHYS.class); factoryMap.put(ChunkHelper.iCCP, PngChunkICCP.class); factoryMap.put(ChunkHelper.tIME, PngChunkTIME.class); factoryMap.put(ChunkHelper.tRNS, PngChunkTRNS.class); factoryMap.put(ChunkHelper.cHRM, PngChunkCHRM.class); factoryMap.put(ChunkHelper.sBIT, PngChunkSBIT.class); factoryMap.put(ChunkHelper.sRGB, PngChunkSRGB.class); factoryMap.put(ChunkHelper.hIST, PngChunkHIST.class); factoryMap.put(ChunkHelper.sPLT, PngChunkSPLT.class); // extended factoryMap.put(PngChunkOFFS.ID, PngChunkOFFS.class); factoryMap.put(PngChunkSTER.ID, PngChunkSTER.class); } /** * Registers a chunk-id (4 letters) to be associated with a PngChunk class *

* This method should be called by user code that wants to add some chunks (not implmemented in this library) to the * factory, so that the PngReader knows about it. */ public static void factoryRegister(String chunkId, Class chunkClass) { factoryMap.put(chunkId, chunkClass); } /** * True if the chunk-id type is known. *

* A chunk is known if we recognize its class, according with factoryMap *

* This is not necessarily the same as being "STANDARD", or being implemented in this library *

* Unknown chunks will be parsed as instances of {@link PngChunkUNKNOWN} */ public static boolean isKnown(String id) { return factoryMap.containsKey(id); } protected PngChunk(String id, ImageInfo imgInfo) { this.id = id; this.imgInfo = imgInfo; this.crit = ChunkHelper.isCritical(id); this.pub = ChunkHelper.isPublic(id); this.safe = ChunkHelper.isSafeToCopy(id); } /** * This factory creates the corresponding chunk and parses the raw chunk. This is used when reading. */ public static PngChunk factory(ChunkRaw chunk, ImageInfo info) { PngChunk c = factoryFromId(ChunkHelper.toString(chunk.idbytes), info); c.length = chunk.len; c.parseFromRaw(chunk); return c; } /** * Creates one new blank chunk of the corresponding type, according to factoryMap (PngChunkUNKNOWN if not known) */ public static PngChunk factoryFromId(String cid, ImageInfo info) { PngChunk chunk = null; try { Class cla = factoryMap.get(cid); if (cla != null) { Constructor constr = cla.getConstructor(ImageInfo.class); chunk = constr.newInstance(info); } } catch (Exception e) { // this can happen for unkown chunks } if (chunk == null) chunk = new PngChunkUNKNOWN(cid, info); return chunk; } protected final ChunkRaw createEmptyChunk(int len, boolean alloc) { ChunkRaw c = new ChunkRaw(len, ChunkHelper.toBytes(id), alloc); return c; } /** * Makes a clone (deep copy) calling {@link #cloneDataFromRead(PngChunk)} */ @SuppressWarnings("unchecked") public static T cloneChunk(T chunk, ImageInfo info) { PngChunk cn = factoryFromId(chunk.id, info); if (cn.getClass() != chunk.getClass()) throw new PngjExceptionInternal("bad class cloning chunk: " + cn.getClass() + " " + chunk.getClass()); cn.cloneDataFromRead(chunk); return (T) cn; } /** * In which "chunkGroup" (see {@link ChunksList}for definition) this chunks instance was read or written. *

* -1 if not read or written (eg, queued) */ final public int getChunkGroup() { return chunkGroup; } /** * @see #getChunkGroup() */ final public void setChunkGroup(int chunkGroup) { this.chunkGroup = chunkGroup; } public boolean hasPriority() { return priority; } public void setPriority(boolean priority) { this.priority = priority; } final void write(OutputStream os) { ChunkRaw c = createRawChunk(); if (c == null) throw new PngjExceptionInternal("null chunk ! creation failed for " + this); c.writeChunk(os); } public int getLength() { return length; } /* * public void setLength(int length) { this.length = length; } */ public long getOffset() { return offset; } public void setOffset(long offset) { this.offset = offset; } /** * Creates the physical chunk. This is used when writing (serialization). Each particular chunk class implements its * own logic. * * @return A newly allocated and filled raw chunk */ public abstract ChunkRaw createRawChunk(); /** * Parses raw chunk and fill inside data. This is used when reading (deserialization). Each particular chunk class * implements its own logic. */ public abstract void parseFromRaw(ChunkRaw c); /** * Makes a copy of the chunk. *

* This is used when copying chunks from a reader to a writer *

* It should normally be a deep copy, and after the cloning this.equals(other) should return true */ public abstract void cloneDataFromRead(PngChunk other); public abstract boolean allowsMultiple(); // this is implemented in PngChunkMultiple/PngChunSingle /** * see {@link ChunkOrderingConstraint} */ public abstract ChunkOrderingConstraint getOrderingConstraint(); @Override public String toString() { return "chunk id= " + id + " (len=" + length + " offset=" + offset + ") c=" + getClass().getSimpleName(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy