001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.plugins.streetside.cubemap;
003
004import java.awt.geom.AffineTransform;
005import java.awt.image.AffineTransformOp;
006import java.awt.image.BufferedImage;
007import java.text.MessageFormat;
008
009import org.apache.log4j.Logger;
010import org.openstreetmap.josm.plugins.streetside.utils.StreetsideProperties;
011
012import javafx.application.Platform;
013import javafx.scene.image.PixelWriter;
014import javafx.scene.image.WritableImage;
015
016@SuppressWarnings({ "restriction"})
017public class GraphicsUtils {
018
019  final static Logger logger = Logger.getLogger(GraphicsUtils.class);
020
021        public static javafx.scene.image.Image convertBufferedImage2JavaFXImage(BufferedImage bf) {
022                WritableImage wr = null;
023                if (bf != null) {
024                        wr = new WritableImage(bf.getWidth(), bf.getHeight());
025                        PixelWriter pw = wr.getPixelWriter();
026                        for (int x = 0; x < bf.getWidth(); x++) {
027                                for (int y = 0; y < bf.getHeight(); y++) {
028                                        pw.setArgb(x, y, bf.getRGB(x, y));
029                                }
030                        }
031                }
032                return wr;
033        }
034
035        public static class PlatformHelper {
036
037        public static void run(Runnable treatment) {
038            if(treatment == null) throw new IllegalArgumentException("The treatment to perform can not be null");
039
040            if(Platform.isFxApplicationThread()) treatment.run();
041            else Platform.runLater(treatment);
042        }
043    }
044
045        public static BufferedImage buildMultiTiledCubemapFaceImage(BufferedImage[] tiles) {
046
047                long start = System.currentTimeMillis();
048
049          BufferedImage res = null;
050
051                int pixelBuffer = StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get()?2:1;
052
053                tiles = cropMultiTiledImages(tiles, pixelBuffer);
054
055                int rows = StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get()?4:2; //we assume the no. of rows and cols are known and each chunk has equal width and height
056        int cols = StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get()?4:2;
057
058        int chunkWidth, chunkHeight;
059
060        chunkWidth = tiles[0].getWidth();
061        chunkHeight = tiles[0].getHeight();
062
063        //Initializing the final image
064        BufferedImage img = new BufferedImage(chunkWidth*cols, chunkHeight*rows, BufferedImage.TYPE_INT_ARGB);
065
066        int num = 0;
067        for (int i = 0; i < rows; i++) {
068            for (int j = 0; j < cols; j++) {
069        // TODO: unintended mirror image created with draw call - requires
070        // extra reversal step - fix!
071        img.createGraphics().drawImage(tiles[num], chunkWidth * j, (chunkHeight * i), null);
072
073        int width = StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get() ? 1014 : 510;
074        int height = StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get() ? 1014 : 510;
075
076        // BufferedImage for mirror image
077        res = new BufferedImage(
078          StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get() ? 1014 : 510,
079          StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get() ? 1014 : 510, BufferedImage.TYPE_INT_ARGB);
080
081        // Create mirror image pixel by pixel
082        for (int y = 0; y < height; y++) {
083          for (int lx = 0, rx = width - 1; lx < width; lx++, rx--) {
084            // lx starts from the left side of the image
085            // rx starts from the right side of the image
086            // lx is used since we are getting pixel from left side
087            // rx is used to set from right side
088            // get source pixel value
089            int p = img.getRGB(lx, y);
090
091            // set mirror image pixel value
092            res.setRGB(rx, y, p);
093          }
094        }
095        num++;
096      }
097    }
098
099    if (StreetsideProperties.DEBUGING_ENABLED.get()) {
100      logger
101        .debug(MessageFormat.format("Image concatenated in {0} seconds.", (System.currentTimeMillis() - start) / 1000));
102    }
103    return res;
104        }
105
106        public static BufferedImage rotateImage(BufferedImage bufImg) {
107                AffineTransform tx = AffineTransform.getScaleInstance(-1, -1);
108            tx.translate(-bufImg.getWidth(null), -bufImg.getHeight(null));
109            AffineTransformOp op = new AffineTransformOp(tx,
110                AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
111            bufImg = op.filter(bufImg, null);
112            return bufImg;
113        }
114
115        private static BufferedImage[] cropMultiTiledImages(BufferedImage[] tiles, int pixelBuffer) {
116
117                long start = System.currentTimeMillis();
118
119          BufferedImage[] res = new BufferedImage[tiles.length];
120
121                        for(int i=0; i<tiles.length;i++) {
122                                if(StreetsideProperties.SHOW_HIGH_RES_STREETSIDE_IMAGERY.get()) {
123                                        res[i] = tiles[i].getSubimage(pixelBuffer, pixelBuffer, 256-pixelBuffer, 256-pixelBuffer);
124                                } else {
125                                        res[i] = tiles[i].getSubimage(pixelBuffer, pixelBuffer, 256-pixelBuffer, 256-pixelBuffer);
126                                }
127                        }
128
129                if(StreetsideProperties.DEBUGING_ENABLED.get()) {
130                        logger.debug(MessageFormat.format("Images cropped in {0}", (System.currentTimeMillis()-start) + " millisecs."));
131                }
132
133                return res;
134        }
135}