package net.sourceforge.gpstools.utils;
/* gpsdings
* Copyright (C) 2007 Moritz Ringler
* $Id: JpegTransformer.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 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.awt.image.BufferedImage;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.RenderingHints;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.awt.geom.Ellipse2D;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.BufferedInputStream;
import java.io.FilterInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Arrays;
import javax.imageio.IIOImage;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.ImageWriter;
import javax.imageio.ImageReader;
import javax.imageio.ImageIO;
import javax.imageio.IIOException;
import javax.imageio.event.IIOWriteWarningListener;
import javax.imageio.stream.ImageInputStream;
import javax.swing.JEditorPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingConstants;
import javax.swing.text.Document;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;
import net.sourceforge.gpstools.exif.ReaderFactory;
import net.sourceforge.gpstools.jpeg.JpegHeader;
/* 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 JpegTransformer {
private transient ImageReader reader;
private transient ImageWriter jpegWriter;
private transient JEditorPane pane;
private float textAlpha = 1.0f;
private int textCorner = SwingConstants.NORTH_EAST;
private float trackPadding = 0.05f;
private float trackAlpha = 1.0f;
private int trackCorner = SwingConstants.NORTH_WEST;
private float trackSize = 0.25f;
private Color[] trackColors = new Color[]{
new Color(0x7ffffff, true), // background, white, 50 % transparent
new Color(0x70000ff, true), // track, blue, 50 % transparent
new Color(0x70ff0000, true) // marker, red, 50 % transparent
};
public static final int C_BACKGROUND = 0;
public static final int C_TRACK = 1;
public static final int C_MARKER = 2;
public JpegTransformer(){
//sole constructor
}
private final IIOWriteWarningListener iioListener = new IIOWriteWarningListener(){
@Override
public void warningOccurred(ImageWriter source, int imageIndex,String warning){
System.err.println(warning);
}
};
public void setTrackColor(int which, Color color){
trackColors[which] = color;
}
public Color getTrackColor(int which){
return trackColors[which];
}
/** Sets the position in the picture where text will be added.
* @param corner the position in compass directions, one of
* {@link javax.swing.SwingConstants#NORTH},
* {@link javax.swing.SwingConstants#NORTH_WEST},
* {@link javax.swing.SwingConstants#NORTH_EAST},
* {@link javax.swing.SwingConstants#SOUTH},
* {@link javax.swing.SwingConstants#SOUTH_WEST},
* {@link javax.swing.SwingConstants#SOUTH_EAST}
* @throws IllegalArgumentException if <code>corner</code> is not one of the
* allowed values.
*/
public void setTextCorner(int corner){
checkCorner(corner);
textCorner = corner;
}
/** Sets the position in the picture where text will be added.
* @param sc the position in compass directions, one of N, NW, NE, S, SW, SE
* @throws IllegalArgumentException if <code>sc</code> is not one of the
* allowed values.
*/
public void setTextCorner(String sc){
setTextCorner(parseCorner(sc));
}
public int getTextCorner(){
return textCorner;
}
public void setTextAlpha(float alpha){
if(alpha < 0.0f || alpha > 1.0f){
throw new IllegalArgumentException("Alpha must be between 0 and 1");
}
textAlpha = alpha;
}
public float getTextAlpha(){
return textAlpha;
}
// TRACK CONFIG
/** Sets the position in the picture where track will be added.
* @param corner the position in compass directions, one of
* {@link javax.swing.SwingConstants#NORTH},
* {@link javax.swing.SwingConstants#NORTH_WEST},
* {@link javax.swing.SwingConstants#NORTH_EAST},
* {@link javax.swing.SwingConstants#SOUTH},
* {@link javax.swing.SwingConstants#SOUTH_WEST},
* {@link javax.swing.SwingConstants#SOUTH_EAST}
* @throws IllegalArgumentException if <code>corner</code> is not one of the
* allowed values.
*/
public void setTrackCorner(int corner){
checkCorner(corner);
trackCorner = corner;
}
/** Sets the position in the picture where track will be added.
* @param sc the position in compass directions, one of N, NW, NE, S, SW, SE
* @throws IllegalArgumentException if <code>sc</code> is not one of the
* allowed values.
*/
public void setTrackCorner(String sc){
setTrackCorner(parseCorner(sc));
}
public int getTrackCorner(){
return trackCorner;
}
/** Sets the padding for the track view.
* @param padding the track view padding in percent of the smaller side of the image
*/
public void setTrackPadding(float padding){
trackPadding = padding;
}
/** Gets the padding for the track view.
* @return the track view padding in percent of the smaller side of the image
*/
public float getTrackPadding(){
return trackPadding;
}
/** Sets the size of the track view.
* @param size the track view size in percent of the smaller side of the image
*/
public void setTrackSize(float size){
trackSize = size;
}
/** Gets the size of the track view.
* @return the track view size in percent of the smaller side of the image
*/
public float getTrackSize(){
return trackSize;
}
public void setTrackAlpha(float alpha){
if(alpha < 0.0f || alpha > 1.0f){
throw new IllegalArgumentException("Alpha must be between 0 and 1");
}
trackAlpha = alpha;
}
public float getTrackAlpha(){
return trackAlpha;
}
private void checkCorner(int corner){
switch(corner){
case SwingConstants.NORTH: //falls through
case SwingConstants.NORTH_WEST: //falls through
case SwingConstants.NORTH_EAST: //falls through
case SwingConstants.SOUTH: //falls through
case SwingConstants.SOUTH_WEST: //falls through
case SwingConstants.SOUTH_EAST: break;
default: throw new IllegalArgumentException(String.valueOf(corner));
}
}
private int parseCorner(String sc){
int corner = SwingConstants.WEST; //used here for illegal value
final int n = sc.length();
if(n == 1 || n == 2){
if(sc.charAt(0) == 'N'){
if (n == 1){
corner = SwingConstants.NORTH;
} else if (sc.charAt(1) == 'W') {
corner = SwingConstants.NORTH_WEST;
} else if (sc.charAt(1) == 'E') {
corner = SwingConstants.NORTH_EAST;
}
} else if(sc.charAt(0) == 'S'){
if (sc.length() == 1){
corner = SwingConstants.SOUTH;
} else if (sc.charAt(1) == 'W') {
corner = SwingConstants.SOUTH_WEST;
} else if (sc.charAt(1) == 'E') {
corner = SwingConstants.SOUTH_EAST;
}
}
}
if(corner == SwingConstants.WEST){
throw new IllegalArgumentException(String.valueOf(corner));
}
return corner;
}
private float calculateScaling(BufferedImage big, Dimension imageDimension){
if(imageDimension == null){
return 1.0f;
}
float width = big.getWidth();
float height = big.getHeight();
float sx = width/imageDimension.width;
float sy = height/imageDimension.height;
return (sy == 0 && sy == 0) ? 1.0f : 1.0f/Math.max(sx, sy);
}
/** Resizes the rendered image using multi-step bilinear interpolation.
@see http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html
*/
private BufferedImage resize(BufferedImage big, float factor){
int w = big.getWidth();
int h = big.getHeight();
final int targetWidth = Math.round(w * factor);
final int targetHeight = Math.round(h * targetWidth/w);
BufferedImage small = big;
do {
Object hint = RenderingHints.VALUE_INTERPOLATION_BICUBIC;
if (w > targetWidth) {
hint = RenderingHints.VALUE_INTERPOLATION_BILINEAR;
w /= 2;
h /= 2;
if (w < targetWidth) {
w = targetWidth;
h = targetHeight;
}
}
BufferedImage tmp = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
final Graphics2D g2 = tmp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(small, 0, 0, w, h, null);
g2.dispose();
small = tmp;
} while (w != targetWidth || h != targetHeight);
return small;
}
private synchronized void initReader(){
if(reader == null){
Iterator<ImageReader> iread = ImageIO.getImageReadersByMIMEType("image/jpeg");
reader = iread.next();
// Avoid the JAI tools image reader if possible
// see http://forums.java.net/jive/thread.jspa?messageID=244212
if (iread.hasNext() &&
reader.getClass().getName().startsWith("com.sun.media.imageioimpl.plugins.jpeg.")){
reader = iread.next();
}
//System.err.println("Using JPEG reader " + reader.getClass().getName());
}
}
private ImageWriter getWriter(){
initReader();
final Iterator<ImageWriter> iwrite =
ImageIO.getImageWritersByMIMEType("image/jpeg");
ImageWriter writer = (jpegWriter == null) ? iwrite.next() : jpegWriter;
final List<String> allowedWriters = (reader == null)
? null
: Arrays.asList(
reader.getOriginatingProvider().getImageWriterSpiNames());
while(true){
final String writerSPI =
writer.getOriginatingProvider().getClass().getName();
if(allowedWriters == null ||
allowedWriters.contains(writerSPI) ||
!iwrite.hasNext()
){
writer.addIIOWriteWarningListener(iioListener);
break;
}
writer.dispose();
writer = iwrite.next();
}
//System.err.println("Using writer " + writer.getClass().getName());
return writer;
}
private InputStream writeTransformedImage(IIOImage image, BufferedImage img)
throws IOException{
/* prepare byteArrayOutputStream and ImageWriter */
final ByteArrayOutputStream bos = new ByteArrayOutputStream();
jpegWriter = getWriter();
jpegWriter.setOutput(ImageIO.createImageOutputStream(bos));
final ImageWriteParam param = jpegWriter.getDefaultWriteParam();
if(param instanceof javax.imageio.plugins.jpeg.JPEGImageWriteParam){
((javax.imageio.plugins.jpeg.JPEGImageWriteParam) param).setOptimizeHuffmanTables(true);
}
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(1.0f);
image.setRenderedImage(img);
/* construct the meta-data for the transformed image
using the jpegWriter default metadata for the technical stuff
(huffman tables and the like) and the exif data from the
original image.
*/
try{
final ImageTypeSpecifier its =
ImageTypeSpecifier.createFromRenderedImage(img);
JpegHeader header = new JpegHeader(
jpegWriter.getDefaultImageMetadata(its, param));
header.insertApp1MarkerNodesFrom(
new JpegHeader(image.getMetadata()));
image.setMetadata(header.getMetadata());
} catch (Exception ex){
System.err.println("Error copying Exif data. Transformed image will have no EXIF data.");
image.setMetadata(null);
}
/* write the transformed image to the ByteArrayOutputStream */
jpegWriter.write(null, image, param);
/* convert the OutputStream to an InputStream and return it */
return new ByteArrayInputStream(bos.toByteArray());
}
/** Returns an InputStream from which the scaled-down image
from the specified file can be read. If the image in the file
is smaller than this JpegTransformer's current imageDimension
it will not be rescaled.
@param file a JPEG JFIF file
@return an InputStream from which a scaled-down JPEG JFIF image can
be read
**/
public synchronized InputStream resize(File file, Dimension maxSize) throws IOException{
InputStream result = null;
if(maxSize != null){
IIOImage image = read(file);
BufferedImage img = (BufferedImage) image.getRenderedImage();
final float factor = calculateScaling(img, maxSize);
if(factor < 1.0f){
System.err.println("Resizing " + file.getName() + ", Factor: " + factor);
img = resize(img, factor);
result = writeTransformedImage(image, img);
}
}
if(result == null){
/* if we don't need to resize simply return an input stream
* that reads from the specified input file */
result = new FileInputStream(file);
}
return result;
}
public InputStream transform(File jpeg, String text, Dimension maxSize)
throws IOException{
return transform(jpeg, text, maxSize, null, null);
}
public InputStream transform(File jpeg, String stamptext, Dimension maxSize, Path2D track, Point2D pt)
throws IOException{
if(maxSize == null && stamptext == null){
return new FileInputStream(jpeg);
}
IIOImage image = read(jpeg);
BufferedImage img = (BufferedImage) image.getRenderedImage();
final float factor = calculateScaling(img, maxSize);
boolean hasChanged = false;
if(factor < 1.0f){
System.err.println("Resizing " + jpeg.getName() + ", Factor: " + factor);
img = resize(img, factor);
hasChanged = true;
}
if(stamptext != null){
System.err.println("Writing geolocation into " + jpeg.getName());
img = stamp(img, stamptext);
hasChanged = true;
}
if (track != null){
System.err.println("Adding track map to " + jpeg.getName());
img = paintTrack(img, track, pt);
hasChanged = true;
}
return ((hasChanged)
? writeTransformedImage(image, img)
: new FileInputStream(jpeg));
}
private Graphics2D setRenderingHints(Graphics2D g2){
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_QUALITY);
return g2;
}
private synchronized BufferedImage paintTrack(BufferedImage img, Path2D track, Point2D pt){
final Rectangle2D trkbnd = track.getBounds2D();
float trkH = (float) trkbnd.getHeight();
float trkW = (float) trkbnd.getWidth();
final int w0 = img.getWidth();
final int h0 = img.getHeight();
BufferedImage trackLayer = new BufferedImage(w0, h0, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = setRenderingHints(trackLayer.createGraphics());
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, 1.0f));
final float scale = getTrackSize() * Math.min(h0, w0)/Math.max(trkH, trkW);
// padding
final float padding = getTrackPadding() * Math.max(trkH, trkW);
final float x = (float) trkbnd.getX() - padding;
final float y = (float) trkbnd.getY() - padding;
trkH = trkH + 2.0f * padding;
trkW = trkW + 2.0f * padding;
trkbnd.setRect(x, y, trkW, trkH);
if (trkH == 0.0f || trkW == 0.0f){
throw new IllegalArgumentException("Empty or 1D track.");
}
final float w = trkW * scale;
final float h = trkH * scale;
int corner = getTrackCorner();
switch(corner){
case SwingConstants.NORTH:
g2.translate((img.getWidth() - w)/2, 0);
break;
case SwingConstants.NORTH_EAST:
g2.translate(img.getWidth() - w, 0);
break;
case SwingConstants.SOUTH_WEST:
g2.translate(0, img.getHeight() - h);
break;
case SwingConstants.SOUTH:
g2.translate((img.getWidth() - w)/2, img.getHeight() - h);
break;
case SwingConstants.SOUTH_EAST:
g2.translate(img.getWidth() - w, img.getHeight() - h);
break;
default:
//north west
}
g2.scale(scale, -scale);
g2.translate(-x, y) ;
g2.setColor(getTrackColor(C_BACKGROUND));
g2.fill(trkbnd);
g2.setStroke(new java.awt.BasicStroke(1/scale));
g2.setColor(getTrackColor(C_TRACK));
g2.draw(track);
g2.setColor(getTrackColor(C_MARKER));
float markerSize = 2/scale; //Math.max(trkH, trkW)/20;
g2.fill(new Ellipse2D.Float((float) pt.getX() - markerSize,
(float) pt.getY() - markerSize,
2 * markerSize, 2 * markerSize));
g2.dispose();
g2 = setRenderingHints(img.createGraphics());
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, getTrackAlpha()));
g2.drawImage(trackLayer, 0, 0, w0, h0, null);
g2.dispose();
return img;
}
private synchronized BufferedImage stamp(BufferedImage img, String text){
final Graphics2D g2 = img.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,
RenderingHints.VALUE_COLOR_RENDER_QUALITY);
if(pane == null){
pane = new JEditorPane();
Kit kit = new Kit();
pane.setEditorKit(kit);
pane.setEditable(false);
pane.setMargin(new java.awt.Insets(0,0,0,0));
pane.setOpaque(false);
}
pane.setText(text);
int w = pane.getPreferredSize().width + 2;
int h = pane.getPreferredSize().height + 2;
switch(getTextCorner()){
case SwingConstants.NORTH:
g2.translate((img.getWidth() - w)/2, 0);
break;
case SwingConstants.NORTH_EAST:
g2.translate(img.getWidth() - w, 0);
break;
case SwingConstants.SOUTH_WEST:
g2.translate(0, img.getHeight() - h);
break;
case SwingConstants.SOUTH:
g2.translate((img.getWidth() - w)/2, img.getHeight() - h);
break;
case SwingConstants.SOUTH_EAST:
g2.translate(img.getWidth() - w, img.getHeight() - h);
break;
default:
//north west
}
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, getTextAlpha()));
java.awt.Container c = new java.awt.Container();
BufferedImage textLayer = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D gt = setRenderingHints(textLayer.createGraphics());
gt.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_OFF);
final int ww = w-2;
final int hh = h-2;
/* paint border */
SwingUtilities.paintComponent(gt, pane, c, 0, 0, ww, hh);
SwingUtilities.paintComponent(gt, pane, c, 1, 0, ww, hh);
SwingUtilities.paintComponent(gt, pane, c, 2, 0, ww, hh);
SwingUtilities.paintComponent(gt, pane, c, 2, 1, ww, hh);
SwingUtilities.paintComponent(gt, pane, c, 2, 2, ww, hh);
SwingUtilities.paintComponent(gt, pane, c, 1, 2, ww, hh);
SwingUtilities.paintComponent(gt, pane, c, 0, 2, ww, hh);
SwingUtilities.paintComponent(gt, pane, c, 0, 1, ww, hh);
/* make border black or white */
int[] px = new int[w*h];
textLayer.getRGB(0,0,w,h, px,0,w);
for(int i=0; i<px.length; i++){
int p = px[i];
if((p >>> 24) != 0){ //don't change transparent pixels
int sat = (p & 0x000000ff) +
((p & 0x0000ff00) >> 8) +
((p & 0x00ff0000) >> 16);
px[i] = (sat >= 381)? 0xaa000000 : 0xaaffffff;
}
}
textLayer.setRGB(0, 0, w, h, px, 0, w);
gt.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
SwingUtilities.paintComponent(gt, pane, c, 1, 1, ww, hh);
gt.dispose();
g2.drawImage(textLayer, 0, 0, w, h, null);
g2.dispose();
return img;
}
private IIOImage read(File jpeg) throws IOException{
initReader();
IIOImage image = null;
/* Read the input image including stream and image meta-data */
do{
ImageInputStream iis =
ImageIO.createImageInputStream(
new BufferedInputStream(new FileInputStream(jpeg)));
try{
reader.setInput(iis);
IIOException iiox = null;
try{
image = reader.readAll(0, null);
} catch (IIOException ex){
iiox = ex;
}
if (iiox != null){
if (iiox.getMessage() != null &&
iiox.getMessage().endsWith("without prior JFIF!") ) {
//We have run into Java bug 4924909
//We try patching the input
System.err.println("Trying workaround for java bug");
System.err.println("http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4924909");
System.err.println("Please vote for this bug!");
iis.close();
iis = patch(jpeg);
reader.setInput(iis);
image = reader.readAll(0, null);
} else {
throw iiox;
}
}
} finally {
iis.close();
}
} while(image == null);
return image;
}
/** Patches a JPEG file that is missing a JFIF marker **/
private static class PatchInputStream extends FilterInputStream{
private static final int[] JFIF = {0xFF,
0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49,
0x46, 0x00, 0x01, 0x02, 0x00, 0x00,
0x01, 0x00, 0x01, 0x00, 0x00};
int position = 0;
public PatchInputStream(InputStream in){
super(in);
}
@Override
public int read() throws IOException{
int result;
if(position < 2){
result = in.read();
} else if (position < 2 + JFIF.length){
result = JFIF[position - 2];
} else {
result = in.read();
}
position++;
return result;
}
@Override
public int read(byte[] b, int off, int len)
throws IOException{
final int max = off + len;
int bytesread = 0;
for(int i=off; i<max; i++){
final int bi = read();
if(bi == -1){
if(bytesread == 0){
bytesread = -1;
}
break;
}
b[i] = (byte) bi;
bytesread++;
}
return bytesread;
}
}
private static ImageInputStream patch(File jpeg) throws IOException{
InputStream in = new FileInputStream(jpeg);
in = new BufferedInputStream(in);
in = new PatchInputStream(in);
return ImageIO.createImageInputStream(in);
}
/* DateTime, Lat, Lon, Ele */
public synchronized InputStream stamp(File jpeg, String text) throws IOException{
IIOImage image = read(jpeg);
final BufferedImage img = (BufferedImage) image.getRenderedImage();
image.setRenderedImage(stamp(img, text));
return writeTransformedImage(image, img);
}
public static Dimension getJPEGDimensionByDecoding(File f) throws IOException{
final BufferedImage image = ImageIO.read(f);
return new Dimension(image.getWidth(), image.getHeight());
}
public synchronized void releaseResources(){
if(reader != null){
reader.dispose();
reader = null;
}
if(jpegWriter != null){
jpegWriter.dispose();
jpegWriter = null;
}
pane = null;
}
public static void main(String[] argv) throws Exception{
JpegTransformer me = new JpegTransformer();
if(argv.length > 2){
me.setTextCorner(argv[2]);
} else {
me.setTextCorner(SwingConstants.NORTH_WEST);
}
if(argv.length > 3){
me.setTextAlpha(Float.parseFloat(argv[3]));
}
String text = argv[1];
File jpeg = new File(argv[0]);
net.sourceforge.gpstools.gpx.Wpt wpt =
(new ReaderFactory()).getReader().readGPSTag(jpeg);
text = (new net.sourceforge.gpstools.utils.GpsPhotoStampFormat(text, null)).format(wpt);
InputStream in = me.transform(jpeg, text, null);
byte[] buffer = new byte[4096];
int count;
while ((count = in.read(buffer, 0, 4096)) != -1) {
System.out.write(buffer, 0, count);
}
}
static class Kit extends HTMLEditorKit {
/**
*
*/
private static final long serialVersionUID = 6031640599826858733L;
// Override createDefaultDocument to force synchronous loading
@Override
public Document createDefaultDocument() {
HTMLDocument doc = (HTMLDocument) super.createDefaultDocument();
doc.setTokenThreshold(Integer.MAX_VALUE);
doc.setAsynchronousLoadPriority(-1);
return doc;
}
}
// /** Prints a DOM xml node (e.g. one created using
// {@link javax.imageio.metadata.IIOMetadata#getAsTree}).
// Makes use of the DOM Level 3 serialization API, so this
// needs Xalan J2 or similar on the class path. */
// private static void printDOMNode(Node node){
// DOMImplementationLS dom = null;
// try{
// dom = (DOMImplementationLS) DOMImplementationRegistry.newInstance().getDOMImplementation("XML LS");
// } catch (Exception ex){
// System.err.println(ex);
// }
// if(dom == null){
// System.err.println("No suitable DOM implementation");
// return;
// }
// LSOutput out = dom.createLSOutput();
// out.setByteStream(System.out);
// out.setEncoding("UTF-8");
// dom.createLSSerializer().write(node, out);
// }
}