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

242 lines
5.9 KiB
Java

package ar.com.hjg.pngj.chunks;
import java.util.ArrayList;
import java.util.List;
import ar.com.hjg.pngj.PngjException;
/**
* We consider "image metadata" every info inside the image except for the most
* basic image info (IHDR chunk - ImageInfo
* class) and the pixels values.
* <p>
* This includes the palette (if present) and all the ancillary chunks
* <p>
* This class provides a wrapper over the collection of chunks of a image (read
* or to write) and provides some high
* level methods to access them
*/
public class PngMetadata {
private final ChunksList chunkList;
private final boolean readonly;
public PngMetadata(ChunksList chunks) {
this.chunkList = chunks;
if (chunks instanceof ChunksListForWrite) {
this.readonly = false;
} else {
this.readonly = true;
}
}
/**
* Queues the chunk at the writer
* <p>
* lazyOverwrite: if true, checks if there is a queued "equivalent" chunk
* and if so, overwrites it. However if that
* not check for already written chunks.
*/
public void queueChunk(final PngChunk c, boolean lazyOverwrite) {
ChunksListForWrite cl = getChunkListW();
if (readonly)
throw new PngjException("cannot set chunk : readonly metadata");
if (lazyOverwrite) {
ChunkHelper.trimList(cl.getQueuedChunks(), new ChunkPredicate() {
public boolean match(PngChunk c2) {
return ChunkHelper.equivalent(c, c2);
}
});
}
cl.queue(c);
}
public void queueChunk(final PngChunk c) {
queueChunk(c, true);
}
private ChunksListForWrite getChunkListW() {
return (ChunksListForWrite) chunkList;
}
// ///// high level utility methods follow ////////////
// //////////// DPI
/**
* returns -1 if not found or dimension unknown
*/
public double[] getDpi() {
PngChunk c = chunkList.getById1(ChunkHelper.pHYs, true);
if (c == null)
return new double[] { -1, -1 };
else
return ((PngChunkPHYS) c).getAsDpi2();
}
public void setDpi(double x) {
setDpi(x, x);
}
public void setDpi(double x, double y) {
PngChunkPHYS c = new PngChunkPHYS(chunkList.imageInfo);
c.setAsDpi2(x, y);
queueChunk(c);
}
// //////////// TIME
/**
* Creates a time chunk with current time, less secsAgo seconds
* <p>
*
* @return Returns the created-queued chunk, just in case you want to
* examine or modify it
*/
public PngChunkTIME setTimeNow(int secsAgo) {
PngChunkTIME c = new PngChunkTIME(chunkList.imageInfo);
c.setNow(secsAgo);
queueChunk(c);
return c;
}
public PngChunkTIME setTimeNow() {
return setTimeNow(0);
}
/**
* Creates a time chunk with diven date-time
* <p>
*
* @return Returns the created-queued chunk, just in case you want to
* examine or modify it
*/
public PngChunkTIME setTimeYMDHMS(int yearx, int monx, int dayx, int hourx, int minx, int secx) {
PngChunkTIME c = new PngChunkTIME(chunkList.imageInfo);
c.setYMDHMS(yearx, monx, dayx, hourx, minx, secx);
queueChunk(c, true);
return c;
}
/**
* null if not found
*/
public PngChunkTIME getTime() {
return (PngChunkTIME) chunkList.getById1(ChunkHelper.tIME);
}
public String getTimeAsString() {
PngChunkTIME c = getTime();
return c == null ? "" : c.getAsString();
}
// //////////// TEXT
/**
* Creates a text chunk and queue it.
* <p>
*
* @param k
* : key (latin1)
* @param val
* (arbitrary, should be latin1 if useLatin1)
* @param useLatin1
* @param compress
* @return Returns the created-queued chunks, just in case you want to
* examine, touch it
*/
public PngChunkTextVar setText(String k, String val, boolean useLatin1, boolean compress) {
if (compress && !useLatin1)
throw new PngjException("cannot compress non latin text");
PngChunkTextVar c;
if (useLatin1) {
if (compress) {
c = new PngChunkZTXT(chunkList.imageInfo);
} else {
c = new PngChunkTEXT(chunkList.imageInfo);
}
} else {
c = new PngChunkITXT(chunkList.imageInfo);
((PngChunkITXT) c).setLangtag(k); // we use the same orig tag (this is not quite right)
}
c.setKeyVal(k, val);
queueChunk(c, true);
return c;
}
public PngChunkTextVar setText(String k, String val) {
return setText(k, val, false, false);
}
/**
* gets all text chunks with a given key
* <p>
* returns null if not found
* <p>
* Warning: this does not check the "lang" key of iTxt
*/
@SuppressWarnings("unchecked")
public List<? extends PngChunkTextVar> getTxtsForKey(String k) {
@SuppressWarnings("rawtypes")
List c = new ArrayList();
c.addAll(chunkList.getById(ChunkHelper.tEXt, k));
c.addAll(chunkList.getById(ChunkHelper.zTXt, k));
c.addAll(chunkList.getById(ChunkHelper.iTXt, k));
return c;
}
/**
* Returns empty if not found, concatenated (with newlines) if multiple! -
* and trimmed
* <p>
* Use getTxtsForKey() if you don't want this behaviour
*/
public String getTxtForKey(String k) {
List<? extends PngChunkTextVar> li = getTxtsForKey(k);
if (li.isEmpty())
return "";
StringBuilder t = new StringBuilder();
for (PngChunkTextVar c : li)
t.append(c.getVal()).append("\n");
return t.toString().trim();
}
/**
* Returns the palette chunk, if present
*
* @return null if not present
*/
public PngChunkPLTE getPLTE() {
return (PngChunkPLTE) chunkList.getById1(PngChunkPLTE.ID);
}
/**
* Creates a new empty palette chunk, queues it for write and return it to
* the caller, who should fill its entries
*/
public PngChunkPLTE createPLTEChunk() {
PngChunkPLTE plte = new PngChunkPLTE(chunkList.imageInfo);
queueChunk(plte);
return plte;
}
/**
* Returns the TRNS chunk, if present
*
* @return null if not present
*/
public PngChunkTRNS getTRNS() {
return (PngChunkTRNS) chunkList.getById1(PngChunkTRNS.ID);
}
/**
* Creates a new empty TRNS chunk, queues it for write and return it to the
* caller, who should fill its entries
*/
public PngChunkTRNS createTRNSChunk() {
PngChunkTRNS trns = new PngChunkTRNS(chunkList.imageInfo);
queueChunk(trns);
return trns;
}
}