package net.sourceforge.gpstools.xmp;
/* gpsdings
* Copyright (C) 2007 Moritz Ringler
* $Id: XMPReader.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.awt.Dimension;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.channels.FileLock;
import java.nio.channels.FileChannel;
import java.nio.ByteBuffer;
import java.util.List;
import net.sourceforge.gpstools.TrackInterpolator;
import net.sourceforge.gpstools.gpx.Wpt;
import net.sourceforge.gpstools.jpeg.*;
/** A class that reads GPS data from XMP metadata in a jpeg header.
It uses JpegStructure to locate the XMP data. **/
public class XMPReader extends AbstractXMPReader{
/** Constructs a new XMPReader. */
public XMPReader(){
//sole constructor
}
@Override
protected ByteBuffer getXMPBytes(File jpeg) throws IOException, XMPReadException{
ByteBuffer result = null;
FileChannel input = (new FileInputStream(jpeg)).getChannel();
FileLock lock = input.tryLock(0L, Long.MAX_VALUE, true);
if(lock == null){
input.close();
throw new IOException("Cannot lock input file.");
}
try{
result = new XMPJpeg(input, false).getXMP();
} finally {
//Do not release lock AFTER closing
lock.release();
input.close();
}
return result;
}
private static int read2bytes(RandomAccessFile raf)
throws IOException
{
int c1, c2;
c1 = raf.read();
if (c1 == -1)
throw new IOException("Premature EOF in JPEG file");
c2 = raf.read();
if (c2 == -1)
throw new IOException("Premature EOF in JPEG file");
return ((c1) << 8) + (c2);
}
/**
* Reads the image size from a SOFX segment.
*/
protected Dimension readImageSize(RandomAccessFile raf, JpegStructure.Segment sofseg)
throws IOException
{
if(sofseg.length < 5){
throw new IOException("Segment " + sofseg + "is too short.");
}
raf.seek(sofseg.offset);
raf.read(); //ignore bitsPerPixel
int height = read2bytes(raf);
int width = read2bytes(raf);
return new Dimension(height, width);
}
/** Returns the jpeg dimension as read from the SOFX header.
**/
@Override
public Dimension readJPEGDimension(File jpeg) throws IOException{
Dimension result = null;
try{
result = readXMP(jpeg).getJpegDimension();
} catch (XMPReadException ex){
//ignore
}
if(result == null || result.width == 0 || result.height == 0){
List<JpegStructure.Segment> segs = null;
JpegStructure structure = new JpegStructure(jpeg);
segs = structure.getAllSegments();
RandomAccessFile raf = new RandomAccessFile(jpeg, "r");
for(JpegStructure.Segment seg : segs){
if(seg.marker.toString().startsWith("SOF")){
result = readImageSize(raf, seg);
if(result != null){
break;
}
}
}
}
return result;
}
/** Main method for testing purposes. Tries to read XMP GPS tags from
all files handed as arguments. **/
public static void main(String[] argv) throws Exception{
XMPReader me = new XMPReader();
TrackInterpolator tp = new TrackInterpolator();
for(String f: argv){
File ff = new File(f);
System.out.println(f);
System.out.println(me.readJPEGDimension(ff));
Wpt pt = me.readGPSTag(ff);
if(pt != null){
tp.printWpt(System.out,pt);
}
}
}
}