当前位置:网站首页>Customized Tile Map cut - based on Tencent map

Customized Tile Map cut - based on Tencent map

2022-06-24 16:21:00 Bug 8

1、 demand

Send a customized hand drawn map on Tencent maps , Because the pixels of hand-painted maps are relatively high , Loading a whole graph is extremely slow . Load the hand drawn map separately according to the tile rules of the map .

2、 Introduction to tile map

https://baike.baidu.com/item/%E7%93%A6%E7%89%87%E5%9C%B0%E5%9B%BE/8006049?fr=aladdin

3、 Tencent superimposes custom tiles api

https://lbs.qq.com/webDemoCenter/javascriptV2/mapType/mapOverlayImage

4、 Idea of tile cutting diagram

  1. Upload hand drawn map source map ;
  2. Pull up the source graph according to the coordinate fixed point ( Because the source image is fine tuned when it is covered on the map ), Get the pull up source diagram ;
  3. Fill the raised source image with surrounding pixels , Generate the cutting source diagram in accordance with the tile diagram format ( Due to the large size of the cutting source diagram , Record only dimensions , The cutting source diagram is not really generated , Avoid server memory overflow );
  4. According to the cutting source diagram parameter information recorded in the previous step , Cut the pull-up source map into tile source map , And fill with surrounding pixels , Get the tile source diagram that meets the specification ;
  5. Step by step cutting of tile source diagram by cycle , And convert the unified tile format (256*256);

5、 Problems encountered and optimization process

1、 How to stretch the source image according to the head and tail coordinates

Explain : Calculate the width height ratio of the lifted image in reverse according to the head and tail coordinates of the source image , Increase the size of the source image by scale ( Only increase the size , Uncompressed dimensions ).

2、 According to the cutting source map, there is an offset between the cut map and the original map

Explain : The size of the resultant cut source graph ( Long 、 wide ) It must be the number of tile slices ( The transverse 、 The longitudinal ) Multiple , Because when cutting tiles, the size is an integer . So when synthesizing the cutting source graph , If the size is not a multiple of the number of tile slices , You need to enlarge the image size to the nearest multiple .

3、 Cut too slowly

Explain : There are many blank transparent graphs in the process of image cutting , No cutting required . Before cutting, judge whether the figure in the corresponding tile size is a full blank figure , If it is a completely blank graph, there is no need to cut the graph .

4、 Server slice memory overflow

4.1、 The size of the hand drawn source image is too large , For example, over 50m There will be insufficient server memory

Explain : Reduce the size of source image properly , Improve the memory configuration of the server .

4.1、 The cutting source image generated from the source image is too large

Explain : The main reason here is that the size of the generated cutting source image is large , You only need to record the parameter information of the cutting source diagram , Do not really generate cutting source graph . Then according to the parameters of the cutting source graph Information , Cut and fill the pull-up source graph , Generate tile source map at specified level . Then cycle to cut the tile source map to get the tile map .

5、 There are jagged tiles

Explain :

The first one is : Improve the pixel quality of the source image .

The second kind :Graphics2D Set the zoom before drawing

/*
 * java Provides 4 Fine tuning options for scaling 
 * image.SCALE_SMOOTH // Smooth first ( Good picture quality 、 The cutting speed is slow )
 * image.SCALE_FAST // Speed first ( Poor picture quality 、 Fast cutting speed )
 * image.SCALE_AREA_AVERAGING // Regional mean ( Good picture quality 、 The cutting speed is slow )
 * image.SCALE_REPLICATE // Pixel duplicate zoom ( Poor picture quality 、 Fast cutting speed )
 * image.SCALE_DEFAULT // Default zoom mode ( Poor picture quality 、 Fast cutting speed )
*/
Image image = bi.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH);

6、 When the cut level is smaller than the theoretical level of the picture , The size of the combined cut source graph is large, resulting in memory overflow

Explain : When the cut layer level is smaller than the theoretical level of the image , The theoretical level shall prevail .

6、 Reference document link

http://www.what21.com/sys/view/java_java-gui_1456896004842.html

https://blog.csdn.net/love_QJP/article/details/81475055

https://blog.csdn.net/mygisforum/article/details/22997879

https://blog.csdn.net/wanm9/article/details/52319061

https://blog.csdn.net/iteye_18766/article/details/82642863

https://blog.csdn.net/iteye_12605/article/details/82240200

7、PictureCutUtil Tool package

package com.example.picturecut.util;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.CropImageFilter;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import static com.sun.org.apache.xalan.internal.lib.ExsltMath.power;

/**
 *  Tencent maps overlay custom tiles tile map Hand drawing processing 
 * @author jdp
 */
public class PictureCutUtil {

    /**
     *  Tencent map - Custom tile cutout 
     * @param fromFile       Source file 
     * @param tempFilePath   Temporary file path 
     * @param group          Cutaway grouping ( only )
     * @param lonStart       Start longitude 
     * @param latStart       Start latitude 
     * @param lonEnd         End longitude 
     * @param latEnd         End latitude 
     * @param cutStartLevel  Slice level starts 
     * @param cutStartLevel  Slice level ends 
     */
    public static void tencentPictureCut(File fromFile, String tempFilePath, String group, double lonStart, double latStart, double lonEnd, double latEnd, Integer cutStartLevel, Integer cutEndLevel){
        String toFilePath = tempFilePath + "/" + group;
        String cutSrcBasePath = tempFilePath + "/" + group +"/cutsrc";
        File toFile = new File(toFilePath + "/cutsrc.png");
        //  Tile cell size px( Default 256)
        int cellPixel = 256;
        //  Slice level range ( Default 14~18 level ), The level of tangency must be <= The theoretical level of the tangent graph 
        if(cutStartLevel==null || cutStartLevel <= 0){
            cutStartLevel = 14;
        }
        if(cutEndLevel==null || cutEndLevel <= 0){
            cutEndLevel = 18;
        }
        //  Synthesize the stretched picture through the head and tail coordinates 
        Map<String, Object> offsetMap = getOffset(lonStart, latStart, lonEnd, latEnd,cellPixel);
        //  Calculate the actual offset dimension 
        //  Source map parameters ( Cut graph theory level )
        double offsetTop = Double.valueOf(offsetMap.get("top").toString());
        double offsetRight = Double.valueOf(offsetMap.get("right").toString());
        double offsetBottom = Double.valueOf(offsetMap.get("bottom").toString());
        double offsetLeft = Double.valueOf(offsetMap.get("left").toString());
        int level = Integer.valueOf(offsetMap.get("level").toString());
        //  If the theoretical level is greater than the tangent level , Start from the theoretical level 
        if(level > cutStartLevel){
            cutStartLevel = level;
        }
        if(cutStartLevel > cutEndLevel){
            cutEndLevel = cutStartLevel;
        }
        //  Composite stretched source image 
        Map<String, Object> cutSrcMap = composeCutSrcPng(fromFile,toFile,offsetTop,offsetRight,offsetBottom,offsetLeft,cellPixel,level);
        //  Source graph parameters after stretching ( Cut graph theory level )
        int cellSize = Integer.valueOf(cutSrcMap.get("standardSize").toString())/(1<<(cutStartLevel-level));
        int realTop = Integer.valueOf(cutSrcMap.get("realTop").toString()) % cellSize;
        int realRight = Integer.valueOf(cutSrcMap.get("realRight").toString()) % cellSize;
        int realBottom = Integer.valueOf(cutSrcMap.get("realBottom").toString()) % cellSize;
        int realLeft = Integer.valueOf(cutSrcMap.get("realLeft").toString()) % cellSize;
        //  Source tile parameters ( Slice start level )
        int[] start = LonLatToXYZ(lonStart, latStart, cutStartLevel);
        int[] end = LonLatToXYZ(lonEnd, latEnd, cutStartLevel);
        //  The height range of the source graph 
        int heightStart = 0;
        int heightEnd = 0;
        for (int y = start[1]; y <= end[1]; y++) {
            //  The width range of the source graph 
            int widthStart = 0;
            int widthEnd = 0;
            //  Calculate the offset of each cell 
            int cellTop = 0;
            int cellBottom = 0;
            //  above 
            if(y == start[1]){
                heightEnd = cellSize - realTop;
                cellTop = realTop;
            }
            //  Lower right 
            else if(y == end[1]){
                heightEnd = heightStart + (cellSize - realBottom);
                cellBottom = realBottom;
            }
            //  The middle part 
            else{
                heightEnd = heightStart + cellSize;
            }
            for (int x = start[0]; x <= end[0]; x++) {
                int cellRight = 0;
                int cellLeft = 0;
                //  On the left 
                if(x == start[0]){
                    widthEnd = cellSize - realLeft;
                    cellLeft = realLeft;
                }
                //  On the right 
                else if(x == end[0]){
                    widthEnd = widthStart + (cellSize - realRight);
                    cellRight = realRight;
                }
                //  The middle part 
                else{
                    widthEnd = widthStart + cellSize;
                }
                //  Source image cutting 
                String cutSrcFilePath = cutSrcBasePath + "/" + cutStartLevel + "-" + x + "-" + y + ".png";
                File cutSrcFile = new File(cutSrcFilePath);
                srcPictureCut(toFile,cutSrcFilePath,widthStart,heightStart,widthEnd,heightEnd);
                //  Source pixel fill 
                resizePng(cutSrcFile,cutSrcFile,0,0,cellTop,cellRight,cellBottom,cellLeft,false);
                //  Cut tile pattern according to source drawing 
                pictureCut(cutSrcFile,toFilePath,256,256,cutStartLevel,cutStartLevel,cutEndLevel,x,y);

                widthStart += widthEnd - widthStart;
            }
            heightStart += heightEnd - heightStart;
        }
        //  Delete the cutting source file 
        deleteAll(new File(cutSrcBasePath));
    }

    public static void srcPictureCut(File srcImageFile, String toFilePath, int widthStart, int heightStart, int widthEnd, int heightEnd) {
        try {
            //  Read source image 
            ImageIO.setUseCache(false);
            BufferedImage bi = ImageIO.read(srcImageFile);
            //  Source width 
            int srcWidth = bi.getWidth();
            //  Source height 
            int srcHeight = bi.getHeight();
            //  Tangent width 
            int cutWidth = widthEnd - widthStart;
            //  Cut height 
            int cutHeight = heightEnd - heightStart;
            //  Source file 
            /*
             * java Provides 4 Fine tuning options for scaling 
             * image.SCALE_SMOOTH // Smooth first ( Good picture quality 、 The cutting speed is slow )
             * image.SCALE_FAST // Speed first ( Poor picture quality 、 Fast cutting speed )
             * image.SCALE_AREA_AVERAGING // Regional mean ( Good picture quality 、 The cutting speed is slow )
             * image.SCALE_REPLICATE // Pixel duplicate zoom ( Poor picture quality 、 Fast cutting speed )
             * image.SCALE_DEFAULT // Default zoom mode ( Poor picture quality 、 Fast cutting speed )
             */
            Image sourceImage = bi.getScaledInstance(srcWidth, srcHeight, Image.SCALE_DEFAULT);
            if(!isTransparent(bi,widthStart,heightStart,widthEnd,heightEnd)){
                //  Draw tangents 
                //  The four parameters are the image starting point coordinates and width and height 
                ImageFilter cropFilter = new CropImageFilter(widthStart, heightStart, widthEnd, heightEnd);
                Image cutImage = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(sourceImage.getSource(), cropFilter));
                BufferedImage cutBufferedImage = new BufferedImage(cutWidth, cutHeight, BufferedImage.TYPE_INT_RGB);
                Graphics2D cutG2d = cutBufferedImage.createGraphics();
                //  Set the background to be fully transparent 
                //  return  BufferedImage Supports specifying transparency , The corresponding data layout and color model  GraphicsConfiguration.
                cutBufferedImage = cutG2d.getDeviceConfiguration().createCompatibleImage(cutWidth, cutHeight, Transparency.TRANSLUCENT);
                cutG2d = cutBufferedImage.createGraphics();
                //  Anti aliasing 
                cutG2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                cutG2d.drawImage(cutImage, 0, 0, null);
                cutG2d.dispose();
                //  Output as file 
                File file = new File(toFilePath);
                if(!file.getParentFile().exists()){
                    file.getParentFile().mkdirs();
                }
                ImageIO.write(cutBufferedImage, "PNG", file);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     *  Tile cutout tool for map adaptation 
     * @param srcImageFile   Source image 
     * @param toFilePath     Slice target file grouping 
     * @param destWidth      Target slice width px
     * @param destHeight     Target slice height px
     * @param level          Picture level 
     * @param cutStartLevel  Slice start level 
     * @param cutEndLevel    Cut end level 
     * @param tileNumberX   x Axis initial tile parameter value 
     * @param tileNumberY   y Axis initial tile parameter value 
     */
    public static void pictureCut(File srcImageFile, String toFilePath, int destWidth, int destHeight, int level,
                                  int cutStartLevel, int cutEndLevel, int tileNumberX, int tileNumberY) {
        try {
            //  Read source image 
            ImageIO.setUseCache(false);
            BufferedImage bi = ImageIO.read(srcImageFile);
            //  Source width 
            int srcWidth = bi.getWidth();
            //  Source height 
            int srcHeight = bi.getHeight();
            //  Tangent width 
            int cutWidth = bi.getWidth();
            //  Cut height 
            int cutHeight = bi.getHeight();
            //  Control the tangent width and height coefficient , Reduce the tangent error 
            int zz = 1;
            // z Coordinate control 
            for (int z = level; z <= cutEndLevel; z++) {
                //  from 【 Slice start level 】 Start cutting 
                if (z >= cutStartLevel && srcWidth >= cutWidth && srcHeight >= cutHeight) {
                    //  Source file 
                    /*
                     * java Provides 4 Fine tuning options for scaling 
                     * image.SCALE_SMOOTH // Smooth first ( Good picture quality 、 The cutting speed is slow )
                     * image.SCALE_FAST // Speed first ( Poor picture quality 、 Fast cutting speed )
                     * image.SCALE_AREA_AVERAGING // Regional mean ( Good picture quality 、 The cutting speed is slow )
                     * image.SCALE_REPLICATE // Pixel duplicate zoom ( Poor picture quality 、 Fast cutting speed )
                     * image.SCALE_DEFAULT // Default zoom mode ( Poor picture quality 、 Fast cutting speed )
                     */
                    Image sourceImage = bi.getScaledInstance(srcWidth, srcHeight, Image.SCALE_DEFAULT);
                    //  Number of slices laterally 
                    int cols = 0;
                    //  Number of slices lengthwise 
                    int rows = 0;
                    //  Calculate the horizontal and vertical number of slices 
                    if (srcWidth % cutWidth == 0) {
                        cols = srcWidth / cutWidth;
                    } else {
                        cols = (int) Math.floor(srcWidth / cutWidth) + 1;
                    }
                    if (srcHeight % cutHeight == 0) {
                        rows = srcHeight / cutHeight;
                    } else {
                        rows = (int) Math.floor(srcHeight / cutHeight) + 1;
                    }
                    //  Loop to create slices ( Transverse slice )
                    for (int i = 0; i < rows; i++) {
                        for (int j = 0; j < cols; j++) {
                            int widthStart = j * cutWidth;
                            int heightStart = i * cutHeight;
                            int widthEnd = (j + 1) * cutWidth;
                            if(widthEnd > srcWidth){
                                widthEnd = srcWidth;
                            }
                            int heightEnd = (i + 1) * cutHeight;
                            if(heightEnd > srcHeight){
                                heightEnd = srcHeight;
                            }
                            if(!isTransparent(bi,widthStart,heightStart,widthEnd,heightEnd)){
                                //  Draw tangents 
                                //  The four parameters are the image starting point coordinates and width and height 
                                ImageFilter cropFilter = new CropImageFilter(widthStart, heightStart, widthEnd, heightEnd);
                                Image cutImage = Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(sourceImage.getSource(), cropFilter));
                                BufferedImage bufferedImage = new BufferedImage(cutWidth, cutHeight, BufferedImage.TYPE_INT_RGB);
                                Graphics2D cutG2d = bufferedImage.createGraphics();
                                //  Set the background to be fully transparent 
                                //  return  BufferedImage Supports specifying transparency , The corresponding data layout and color model  GraphicsConfiguration.
                                bufferedImage = cutG2d.getDeviceConfiguration().createCompatibleImage(cutWidth, cutHeight, Transparency.TRANSLUCENT);
                                cutG2d = bufferedImage.createGraphics();
                                //  Anti aliasing 
                                cutG2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                                cutG2d.drawImage(cutImage, 0, 0, null);
                                cutG2d.dispose();
                                //  Draw the reduced tile map through the cut image 
                                if(destWidth != 0 && destHeight != 0){
                                    /*
                                     * java Provides 4 Fine tuning options for scaling 
                                     * image.SCALE_SMOOTH // Smooth first ( Good picture quality 、 The cutting speed is slow )
                                     * image.SCALE_FAST // Speed first ( Poor picture quality 、 Fast cutting speed )
                                     * image.SCALE_AREA_AVERAGING // Regional mean ( Good picture quality 、 The cutting speed is slow )
                                     * image.SCALE_REPLICATE // Pixel duplicate zoom ( Poor picture quality 、 Fast cutting speed )
                                     * image.SCALE_DEFAULT // Default zoom mode ( Poor picture quality 、 Fast cutting speed )
                                     */
                                    Image destImage = bufferedImage.getScaledInstance(destWidth, destHeight, Image.SCALE_SMOOTH);
                                    bufferedImage = new BufferedImage(destWidth, destHeight, BufferedImage.TYPE_INT_RGB);
                                    Graphics2D destG2d = bufferedImage.createGraphics();
                                    //  Set the background to be fully transparent 
                                    //  return  BufferedImage Supports specifying transparency , The corresponding data layout and color model  GraphicsConfiguration.
                                    bufferedImage = destG2d.getDeviceConfiguration().createCompatibleImage(destWidth, destHeight, Transparency.TRANSLUCENT);
                                    destG2d = bufferedImage.createGraphics();
                                    //  Anti aliasing 
                                    destG2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                                    destG2d.drawImage(destImage, 0, 0, null);
                                    destG2d.dispose();
                                }
                                //  Output as file 
                                File file = new File(toFilePath + "/" + z + "/" + z + "-" + (j + tileNumberX) + "-" + (i + tileNumberY) + ".png");
                                if(!file.getParentFile().exists()){
                                    file.getParentFile().mkdirs();
                                }
                                ImageIO.write(bufferedImage, "PNG", file);
                            }
                        }
                    }
                }
                //  Tile parameter value reset 
                tileNumberY *= 2;
                tileNumberX *= 2;
                //  Slice parameter width height reset 
                cutWidth = (int) Math.ceil(1.0*srcWidth / (1 << zz));
                cutHeight = (int) Math.ceil(1.0*srcHeight / (1 << zz));
                zz++;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     *  tailoring 、 The tensile 、 Compress PNG Picture tool class 
     * @param fromFile      Source file 
     * @param toFile        Cropped file 
     * @param outputWidth   Cut width px( Less than or equal to 0 Use the original drawing size )
     * @param outputHeight  Cutting height px( Less than or equal to 0 Use the original drawing size )
     * @param offsetTop     Upper axis offset ( The upper left corner is the benchmark )
     * @param offsetRight   Right axis offset ( The upper left corner is the benchmark )
     * @param offsetBottom  Lower axis offset ( The upper left corner is the benchmark )
     * @param offsetLeft    Left axis offset ( The upper left corner is the benchmark )
     * @param proportion    Whether it is proportional scaling 
     */
    public static void resizePng(File fromFile, File toFile, int outputWidth, int outputHeight, int offsetTop, int offsetRight, int offsetBottom, int offsetLeft, boolean proportion) {
        try {
            ImageIO.setUseCache(false);
            BufferedImage bi = ImageIO.read(fromFile);
            if (outputWidth <= 0) {
                outputWidth = bi.getWidth();
            }
            if (outputHeight <= 0) {
                outputHeight = bi.getHeight();
            }
            int newWidth;
            int newHeight;
            //  Determine whether it is proportional scaling 
            if (proportion) {
                //  Calculate the width and height of the output picture for proportional scaling 
                double rate1 = ((double) bi.getWidth(null)) / (double) outputWidth + 0.1;
                double rate2 = ((double) bi.getHeight(null)) / (double) outputHeight + 0.1;
                //  Zoom control according to the large zoom ratio 
                double rate = rate1 < rate2 ? rate1 : rate2;
                newWidth = (int) (((double) bi.getWidth(null)) / rate);
                newHeight = (int) (((double) bi.getHeight(null)) / rate);
            } else {
                //  Output picture width 
                newWidth = outputWidth;
                //  The height of the output picture 
                newHeight = outputHeight;
            }
            /*
             * java Provides 4 Fine tuning options for scaling 
             * image.SCALE_SMOOTH // Smooth first ( Good picture quality 、 The cutting speed is slow )
             * image.SCALE_FAST // Speed first ( Poor picture quality 、 Fast cutting speed )
             * image.SCALE_AREA_AVERAGING // Regional mean ( Good picture quality 、 The cutting speed is slow )
             * image.SCALE_REPLICATE // Pixel duplicate zoom ( Poor picture quality 、 Fast cutting speed )
             * image.SCALE_DEFAULT // Default zoom mode ( Poor picture quality 、 Fast cutting speed )
             */
            Image image = bi.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH);
            BufferedImage bufferedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
            Graphics2D g2d = bufferedImage.createGraphics();
            //  Set the background to be fully transparent 
            //  return  BufferedImage Supports specifying transparency , The corresponding data layout and color model  GraphicsConfiguration.
            System.err.println("【 Cutaway 】 New composite size :"+(newWidth + offsetLeft + offsetRight)+"x"+(newHeight + offsetTop + offsetBottom));
            bufferedImage = g2d.getDeviceConfiguration().createCompatibleImage(newWidth + offsetLeft + offsetRight, newHeight + offsetTop + offsetBottom, Transparency.TRANSLUCENT);
            g2d.dispose();
            g2d = bufferedImage.createGraphics();
            //  Anti aliasing 
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.drawImage(image, offsetLeft, offsetTop, null);
            g2d.dispose();
            if(!toFile.getParentFile().exists()){
                toFile.getParentFile().mkdirs();
            }
            ImageIO.write(bufferedImage, "PNG", toFile);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     *  According to the tile parameters and offset, the cutting source map is synthesized 
     * @param fromFile   Source file 
     * @param toFile     Target file 
     * @param offsetTop  Upper offset 
     * @param offsetRight    Right offset 
     * @param offsetBottom   Lower offset 
     * @param offsetLeft     Left offset 
     * @param cellPixel  Tile pixels 
     * @param tileLevel  Source graph theory level 
     */
    public static Map<String,Object> composeCutSrcPng(File fromFile, File toFile, double offsetTop, double offsetRight, double offsetBottom, double offsetLeft, int cellPixel, int tileLevel) {
        Map<String, Object> map = new HashMap<String, Object>();
        //  Pictures occupy pixels 
        double posseWidth = cellPixel-offsetLeft-offsetRight;
        double posseHeight = cellPixel-offsetTop-offsetBottom;
        try {
            //  Calculate the actual offset dimension of the original drawing 
            ImageIO.setUseCache(false);
            BufferedImage bufferedImage = ImageIO.read(fromFile);
            //  Source image size 
            int width = bufferedImage.getWidth();
            int height = bufferedImage.getHeight();
            //  The size of the stretched picture 
            int tensileWidth = width;
            int tensileHeight = height;
            if(width > height){
                tensileHeight = (int) Math.round(width*posseHeight/posseWidth);
                //  The zoom 
                if(tensileHeight < height){
                    tensileHeight = height;
                    tensileWidth = (int) Math.round(height*(posseWidth)/(posseHeight));
                }
            }else{
                tensileWidth = (int) Math.round(height*(posseWidth)/(posseHeight));
                //  The zoom 
                if(tensileWidth < width){
                    tensileWidth = width;
                    tensileHeight = (int) Math.round(width*posseHeight/posseWidth);
                }
            }
            //  Calculate the actual offset of the stretched picture 
            double realTop = offsetTop*tensileHeight/posseHeight;
            double realRight = offsetRight*tensileWidth/posseWidth;
            double realBottom = offsetBottom*tensileHeight/posseHeight;
            double realLeft = offsetLeft*tensileWidth/posseWidth;
            //  Automatically generate the original drawing with reasonable size 
            int widthTotal = (int) Math.round(tensileWidth + realRight + realLeft);
            int heightTotal = (int) Math.round(tensileHeight + realTop + realBottom);
            //  Automatically optimize the picture to square , And generate corresponding tileLevel Standard size pictures of levels , Reduce the tangent error 
            //  The standard size of the cut 
            int standardSize = 0;
            //  Corresponding level horizontal ( Or vertically ) Number of cut pictures 
            int zoom = 1 << (18-tileLevel);
            //  Calculate the actual offset dimension of standard dimension cutting drawing 
            if(widthTotal >= heightTotal){
                standardSize = (int) (Math.ceil(1.0*widthTotal/zoom)*zoom);
            }else if(widthTotal < heightTotal){
                standardSize = (int) (Math.ceil(1.0*heightTotal/zoom)*zoom);
            }
            int widthPadding = (standardSize - widthTotal);
            int heightPadding = (standardSize - heightTotal);
            if(widthPadding != 0){
                int rightNum = (int) (widthPadding*realRight/widthTotal);
                int leftNum = (int) (widthPadding*realLeft/widthTotal);
                realRight += rightNum;
                realLeft += leftNum;
                tensileWidth += widthPadding - rightNum - leftNum;
            }
            if(heightPadding != 0){
                int topNum = (int) (heightPadding*realTop/heightTotal);
                int bottomNum = (int) (heightPadding*realBottom/heightTotal);
                realTop += topNum;
                realBottom += bottomNum;
                tensileHeight += heightPadding - topNum - bottomNum;
            }
            //  Generate the stretched picture 
            resizePng(fromFile,toFile,tensileWidth,tensileHeight,0,0,0,0,false);
            //  Return the offset parameter information 
            map.put("standardSize",standardSize);
            map.put("tensileWidth",tensileWidth);
            map.put("tensileHeight",tensileHeight);
            map.put("realTop",(int)Math.round(realTop));
            map.put("realRight",(int)Math.round(realRight));
            map.put("realBottom",(int)Math.round(realBottom));
            map.put("realLeft",(int)Math.round(realLeft));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    /**
     *  Google down converts the layer row corresponding to latitude and longitude 
     *
     * @param lon   longitude 
     * @param lat   dimension 
     * @param zoom  In the zoom Layer to convert 
     * @return
     */
    public static int[] LonLatToXYZ(double lon, double lat, int zoom) {
        double n = Math.pow(2, zoom);
        double tileX = ((lon + 180) / 360) * n;
        double tileY = (1 - (Math.log(Math.tan(Math.toRadians(lat)) + (1 / Math.cos(Math.toRadians(lat)))) / Math.PI)) / 2 * n;
        int[] xy = new int[2];
        xy[0] = (int) Math.floor(tileX);
        xy[1] = (int) Math.floor(tileY);
        return xy;
    }

    /**
     *  Tile parameters to longitude and latitude 
     *
     * @param x  Longitude tile parameters 
     * @param y  Latitude tile parameters 
     * @param z z Axis level 
     * @return
     */
    public static double[] XYZtoLonlat(int x, int y, int z) {
        double n = Math.pow(2, z);
        double lon = x / n * 360.0 - 180.0;
        double lat = Math.atan(Math.sinh(Math.PI * (1 - 2 * y / n)));
        lat = lat * 180.0 / Math.PI;
        double[] lonlat = new double[2];
        lonlat[0] = lon;
        lonlat[1] = lat;
        return lonlat;
    }

    /**
     *  Longitude to pixels X value 
     * @param lon    longitude 
     * @param level z Axis level 
     * @return
     */
    static double lonToPixel(double lon, int level) {
        return (lon + 180) * (256 << level) / 360;

    }

    /**
     *  Pixels X To longitude 
     * @param pixelX     Pixels X
     * @param level z Axis level 
     * @return
     */
    static double pixelToLon(double pixelX, int level) {
        return pixelX * 360 / (256 << level) - 180;

    }

    /**
     *  Latitude to pixels Y
     * @param lat    latitude 
     * @param level z Axis level 
     * @return
     */
    static double latToPixel(double lat, int level) {
        double siny = Math.sin(lat * Math.PI / 180);
        double y = Math.log((1 + siny) / (1 - siny));
        return (128 << level) * (1 - y / (2 * Math.PI));
    }

    /**
     *  Pixels Y To latitude 
     * @param pixelY     Pixels Y
     * @param level z Axis level 
     * @return
     */
    static double pixelToLat(double pixelY, int level) {
        //  Of course, it can be more accurate 
        final double E = 2.7128;
        double y = 2 * Math.PI * (1 - pixelY / (128 << level));
        double z = power(E, y);
        double siny = (z - 1) / (z + 1);
        return Math.asin(siny) * 180 / Math.PI;
    }

    /**
     *  Determine the top right, bottom left offset of the picture according to the level 
     * @param lonStar        Start longitude 
     * @param latStar        Start latitude 
     * @param lonEnd         End longitude 
     * @param latEnd         End latitude 
     * @param cellPixel      Tile cell size px( Default 256)
     * @return
     */
    public static Map<String, Object> getOffset(double lonStar, double latStar, double lonEnd, double latEnd, int cellPixel) {
        int[] star = {};
        int[] end = {};
        //  Cut graph theory level 
        int level = 18;
        do {
            star = LonLatToXYZ(lonStar, latStar, level);
            end = LonLatToXYZ(lonEnd, latEnd, level);
            level--;
        } while (star[0] != end[0] || star[1] != end[1]);
        Map<String, Object> map = new HashMap<String, Object>();
        level += 1;
        int[] tileNumber = LonLatToXYZ(lonStar, latStar, level);
        int tileNumberX = tileNumber[0];
        int tileNumberY = tileNumber[1];
        map.put("level", level);
        map.put("top", latToPixel(latStar, level) - (cellPixel * tileNumberY));
        map.put("right", cellPixel * (tileNumberX + 1) - lonToPixel(lonEnd, level));
        map.put("bottom", cellPixel * (tileNumberY + 1) - latToPixel(latEnd, level));
        map.put("left", lonToPixel(lonStar, level) - (cellPixel * tileNumberX));
        map.put("tileNumberX", tileNumber[0]);
        map.put("tileNumberY", tileNumber[1]);
        return map;
    }

    /**
     *  Determine whether the image is a pure transparent background image 
     * @param bufImg         Picture stream 
     * @param widthStart     Judge the starting point of width 
     * @param heightStart    Judge the high starting point 
     * @param widthEnd       Judge the end of the width 
     * @param heightEnd      Judge the high end point 
     * @return
     */
    public static boolean isTransparent(BufferedImage bufImg, int widthStart, int heightStart, int widthEnd, int heightEnd){
        widthStart = widthStart<=0?0:widthStart;
        heightStart = heightStart<=0?0:heightStart;
        widthEnd = widthEnd<=0?bufImg.getWidth():widthEnd;
        heightEnd = heightEnd<=0?bufImg.getHeight():heightEnd;
        for (int i = widthStart; i < widthEnd; i++) {
            for (int j = heightStart; j < heightEnd; j++) {
                int pixel = bufImg.getRGB(i, j);
                if (pixel >> 24 != 0) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     *  Get all files in the current folder 
     * @param path
     * @param allfilelist
     * @return
     */
    public static ArrayList<File> getallfile(File path, ArrayList<File> allfilelist) {
        //  Path exists 
        if (path.exists()) {
            //  Determine if the file is a folder , If it is , Start recursion 
            if (path.isDirectory()) {
                File f[] = path.listFiles();
                for (File file2 : f) {
                    getallfile(file2, allfilelist);
                }
            } else {
                allfilelist.add(path);
            }
        }
        return allfilelist;
    }

    /**
     *  Delete all files 
     * @param path
     */
    public static void deleteAll(File path) {
        //  Path exists 
        if (!path.exists()){
            return;
        }
        //  It's a document 
        if (path.isFile()){
            path.delete();
            return;
        }
        File[] files = path.listFiles();
        for (int i = 0; i < files.length; i++) {
            deleteAll(files[i]);
        }
        path.delete();
    }

    public static void main(String[] args) throws IOException {
        String group = "djy-test";
        String tempFilePath = "C:/myFile/pictureCut";
//        String toFilePath = tempFilePath + "/" +  group+ "/djy-big.png";
//        String drawingMapImg = "https://htwz-wzy.obs.cn-north-4.myhuaweicloud.com:443/htwz-wzy/4199caf6-7d76-442f-b89d-60fc38d36fb3%E9%83%BD%E6%B1%9F%E5%A0%B0-huqingqing.png";
//        URL url = new URL(drawingMapImg);
//        FileUtils.copyURLToFile(url, new File(toFilePath));
//        File fromFile = new File(toFilePath);
        File fromFile = new File(tempFilePath + "/djy-src.png");

        //  Slice start level 
        int cutStartLevel = 11;
        int cutEndLevel = 18;
        //  Head coordinate 
        double lon1 = 103.604822;
        double lat1 = 31.00991;
        //  Tail coordinates 
        double lon2 = 103.618107;
        double lat2 = 30.993703;

//        //  Stretch coordinates 
//        //  Head coordinate 
//        double lon1 = 103.60408;
//        double lat1 = 31.012203;
//        //  Tail coordinates 
//        double lon2 = 103.62408;
//        double lat2 = 30.992203;

        Date currDate = new Date();
        tencentPictureCut(fromFile,tempFilePath, group, lon1, lat1, lon2, lat2, cutStartLevel, cutEndLevel);
        System.out.println(" Total time :" + ((new Date()).getTime() - currDate.getTime()) / 1000);
        //  Source file deletion 
//        fromFile.delete();
    }
}
原网站

版权声明
本文为[Bug 8]所创,转载请带上原文链接,感谢
https://yzsam.com/2021/04/20210427190252021m.html

随机推荐