    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}