Package net.sourceforge.gpstools.utils

Source Code of net.sourceforge.gpstools.utils.JpegTransformer$Kit

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);
    // }

}
TOP

Related Classes of net.sourceforge.gpstools.utils.JpegTransformer$Kit

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.