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