package net.sourceforge.gpstools.jpeg;
/* gpsdings
* Copyright (C) 2007 Moritz Ringler
* $Id: JpegHeader.java 358 2008-11-24 19:06:17Z ringler $
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//import org.w3c.dom.DOMImplementationList;
//import org.w3c.dom.bootstrap.DOMImplementationRegistry;
//import org.w3c.dom.ls.DOMImplementationLS;
//import org.w3c.dom.ls.LSOutput;
//import org.w3c.dom.ls.LSSerializer;
import java.util.List;
import java.awt.Dimension;
import java.util.ArrayList;
import javax.imageio.metadata.IIOMetadata;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/* see also http://tinyurl.com/2ajlkq#EXIFReadJPEG */
/* $ java -cp gpsdings.jar net.sourceforge.gpstools.utils.JpegTransformer test/guffert_IMG_0877_2006-10-03T113835.jpg '<html><font color="black" face="Arial"><b>{lat}
{lon}<br>{ele} m<br>{dateTime}</b></font></html>' N > test.jpg
*/
public class JpegHeader {
public final static String METADATA_FORMAT = "javax_imageio_jpeg_image_1.0";
private final IIOMetadata imeta;
public JpegHeader(IIOMetadata metadata){
if(metadata == null){
throw new NullPointerException("Metadata may not be null.");
}
imeta = metadata;
}
/** Retrieves a Exif or XMP nodes.
* @return all
* <code>/markerSequence/unknown[@MarkerTag = '255']</code>
* nodes from the DOM representation of this jpeg header or <code>null</code>
*/
public Node[] getApp1MarkerNodes(){
List<Node> result = new ArrayList<Node>();
Node meta = imeta.getAsTree(METADATA_FORMAT);
final List<Node> markers = getChildren(meta, "markerSequence");
for (Node marker : markers){
List<Node> unknownNodes = getChildren(marker, "unknown");
for (Node unknown : unknownNodes){
NamedNodeMap att = unknown.getAttributes();
if(att != null){
Node markerTagAtt = att.getNamedItem("MarkerTag");
if(
markerTagAtt != null &&
markerTagAtt.getNodeValue().equals("225")
){
result.add(unknown);
}
}
}
}
return result.toArray(new Node[result.size()]);
}
public Dimension getImageDimension(){
Node meta = imeta.getAsTree("javax_imageio_1.0");
final List<Node> nodelist = getChildren(meta, "Dimension");
Dimension result = null;
if(!nodelist.isEmpty()){
Node dim = nodelist.get(0);
Integer width = extractValue(dim, "HorizontalPixelSize");
Integer height = extractValue(dim, "VerticalPixelSize");
if(width != null && height != null){
result = new Dimension(width.intValue(), height.intValue());
}
}
return result;
}
private static Integer extractValue(Node dim, String child){
List<Node> nodes = getChildren(dim, child);
if(nodes.isEmpty()){
return null;
}
Node childnode = nodes.get(0);
Node val = childnode.getAttributes().getNamedItem("value");
if(val == null || val.getNodeValue() == null){
return null;
}
try{
return Integer.valueOf(val.getNodeValue());
} catch (NumberFormatException nfx){
return null;
}
}
public void insertApp1MarkerNodesFrom(JpegHeader src)
throws javax.imageio.metadata.IIOInvalidTreeException{
insertMarkerNodes(src.getApp1MarkerNodes());
}
/** Inserts nodes returned from the {@link #getApp1MarkerNodes} method
* into the specified metadata.
*/
private boolean insertMarkerNodes(Node[] newnodes)
throws javax.imageio.metadata.IIOInvalidTreeException{
boolean result = false;
Node meta = imeta.getAsTree(METADATA_FORMAT);
if(newnodes != null && newnodes.length != 0){
final List<Node> markers = getChildren(meta, "markerSequence");
if(!markers.isEmpty()){
Node node = markers.get(0);
for(int i = newnodes.length - 1; i >= 0; i--){
node.insertBefore(newnodes[i], node.getFirstChild());
}
imeta.setFromTree(METADATA_FORMAT, meta);
result = true;
}
}
return result;
}
/** Returns a list of child nodes with the specified local name.
* @param parent the node whose children you want to retrieve
* @param localName the local name of the child nodes you want
* to retrieve
*/
private static List<Node> getChildren(Node parent, String localName){
List<Node> result = new ArrayList<Node>();
final NodeList childNodes = parent.getChildNodes();
final int n = childNodes.getLength();
for(int i=0; i<n; i++){
if(childNodes.item(i).getLocalName().equals(localName)){
result.add(childNodes.item(i));
}
}
return result;
}
public IIOMetadata getMetadata(){
return imeta;
}
}