Package net.sourceforge.gpstools.xmp

Source Code of net.sourceforge.gpstools.xmp.AbstractXMPReader$CharBufferReader

package net.sourceforge.gpstools.xmp;

/* gpsdings
* Copyright (C) 2007 Moritz Ringler
* $Id: AbstractXMPReader.java 441 2010-12-13 20:04:20Z 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 java.io.File;
import java.io.Reader;
import java.io.IOException;
import java.util.Calendar;
import java.util.TimeZone;
import java.util.Date;
import java.nio.charset.Charset;
import java.nio.CharBuffer;
import java.nio.ByteBuffer;
import java.text.ParseException;
import org.xml.sax.SAXException;
import net.sourceforge.gpstools.gpx.Wpt;
import net.sourceforge.gpstools.exif.GpsExifReader;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;

/** A class that reads GPS data from XMP metadata in a jpeg header.
    It uses Java Advanced Image I/O to retrieve the metadata and
    SAX to parse the XMP data. Therefore it has no external library dependencies.
    <p>
    Based on the 2005 Adobe XMP Specification. **/
public abstract class AbstractXMPReader implements GpsExifReader{
    private transient XMPHandler xmphandler;
    private final transient Object lockobj = new Object();
    public final static String XMP_NAMESPACE = "http://ns.adobe.com/xap/1.0/";
    /** Constructs a new AbstractXMPReader. */
    public AbstractXMPReader(){
        //sole constructor
    }

    protected abstract ByteBuffer getXMPBytes(File jpeg) throws IOException, XMPReadException;

    /** Retrieves and decodes the XMP data in meta.
    * @return an XMP document or <code>null</null> if no XMP node was found
    **/
    protected static CharBuffer getXMPChars(ByteBuffer xmpBytes){
        CharBuffer result = null;
        if(xmpBytes != null){
            Charset utf8 = Charset.forName("utf-8");
            result = utf8.decode(xmpBytes);
        }
        return(result);
    }


    /** Looks for XMP metadata in the specified jpeg file and if successfull
     * extracts GPS information from it and returns it.
     * @return a GPX waypoint if an XMP document containing at
     * least latitude and longitude
     * information was found, <code>null</code> otherwise
     **/
    @Override
    public Wpt readGPSTag(File jpeg) throws IOException{
        Wpt gps = null;
        XMPProperties xmp = null;
        try{
            xmp = readXMP(jpeg);
        } catch (XMPReadException xrx){
            throw xrx.toIOException();
        }
        if(xmp != null){
            gps = xmp.getWpt();
            //System.out.println(gps.getLat());
            //System.out.println(gps.getLon());
            if (
                gps != null &&
                (gps.getLat() == null || gps.getLon() == null)
            ){
               gps = null;
            }
        }
        if(gps == null){
            throw new IOException("No XMP GPS information found in " + jpeg.getPath());
        }
        return gps;
    }

    protected XMPProperties readXMP(File jpeg) throws IOException, XMPReadException{
        ByteBuffer buff = getXMPBytes(jpeg);
        CharBuffer xmpChars = getXMPChars(buff);
        //System.out.println(xmpChars.toString());
        XMPProperties result = null;
        if(xmpChars != null){
            result = parseXMP(xmpChars);
        }
        return result;
    }

    /** Returns the local dateTime that results from parsing <code>str</code>
        and adding the utc offset of the timezone specified in <code>str</code>.
     **/
    @Override
    public Date parseExifDate(String str) throws ParseException{
        Calendar cal = XMPHandler.parseDate(str);
        return (cal == null)? null : toLocalDate(cal);
    }

    private static Date toLocalDate(Calendar cal){
        TimeZone tz = cal.getTimeZone();
        long utcDate = cal.getTime().getTime();
        return new Date(utcDate + tz.getOffset(utcDate));
    }

    /** Returns the local time that results from reading the
        exif:DateTimeOriginal xmp property <em>ignoring</em>
        the time zone specifier. This is useful when XMP must
        be handled in the same way as Exif, which lacks time
        zone information. **/
    @Override
    public Date readOriginalTime(File jpeg) throws IOException{
        Calendar cal = null;
        try{
            cal = getOriginalTime(jpeg);
        } catch (XMPReadException xrx){
            throw xrx.toIOException();
        }
        return (cal == null)? null : toLocalDate(cal);
    }

    /** Returns the date and time that result from reading the
        exif:DateTimeOriginal xmp property <em>including</em>
        the time zone specifier. **/
    public Calendar getOriginalTime(File jpeg) throws XMPReadException, IOException{
        XMPProperties xmp = readXMP(jpeg);
        return (xmp == null)? null : xmp.getTime();
    }

    /** Extracts information from a decoded XMP document and returns it
     * as a GPX waypoint object.
     * @return a GPX waypoint if at least latitude and longitude
     * information was found in the XMP document, <code>null</code> otherwise
     **/
    synchronized XMPProperties parseXMP(CharBuffer text) throws XMPReadException, IOException{
        try {
            XMLReader reader = XMLReaderFactory.createXMLReader();
            reader.setFeature("http://xml.org/sax/features/namespaces", true);
            reader.setFeature("http://xml.org/sax/features/namespace-prefixes", false);
            synchronized(lockobj){
                if(xmphandler == null){
                    xmphandler = new XMPHandler();
                }
            }
            reader.setContentHandler(xmphandler);
            InputSource in = new InputSource(new CharBufferReader(text));
            reader.parse(in);
        } catch (SAXException ex){
            throw new XMPReadException(ex);
        }
        return xmphandler.getParseResult();
    }

    /** Wraps a CharBuffer as a reader. Needed because you cannot construct
        a SAX InputSource directly on a CharBuffer or Readable. **/
    private static class CharBufferReader extends Reader{
        private final CharBuffer buffer;
        public CharBufferReader(CharBuffer buff){
            buffer = buff;
        }

        @Override
        public int read(char[] cbuf, int off, int len){
            if(!buffer.hasRemaining()){
                return -1;
            }
            int bytesToRead = Math.min(len, buffer.remaining());
            buffer.get(cbuf, off, bytesToRead);
            return bytesToRead;
        }

        @Override
        public void close(){
            // do nothing.
        }
    }

}
TOP

Related Classes of net.sourceforge.gpstools.xmp.AbstractXMPReader$CharBufferReader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.