当前位置:网站首页>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
- Upload hand drawn map source map ;
- 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 ;
- 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 );
- 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 ;
- 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(); } }
边栏推荐
- Goby+awvs realize attack surface detection
- Using alicloud RDS for SQL Server Performance insight to optimize database load - first understanding of performance insight
- Embedded Software Engineer written interview guide arm system and architecture
- Percona Toolkit series - Pt deadlock logger
- MySQL InnoDB and MyISAM
- SIGGRAPH 2022 | 真实还原手部肌肉,数字人双手这次有了骨骼、肌肉、皮肤
- Pageadmin CMS solution for redundant attachments in website construction
- Cause analysis of the failure of web page live broadcast on demand RTMP streaming platform easydss streaming live broadcast
- MD5 verification based on stm32
- Logging is not as simple as you think
猜你喜欢
C. Three displays(动态规划)Codeforces Round #485 (Div. 2)
Cap: multiple attention mechanism, interesting fine-grained classification scheme | AAAI 2021
Wechat official account debugging and natapp environment building
【面试高频题】难度 3/5,可直接构造的序列 DP 题
Cognition and difference of service number, subscription number, applet and enterprise number (enterprise wechat)
Applet - use of template
用 Oasis 开发一个跳一跳(一)—— 场景搭建
A new weapon to break the memory wall has become a "hot search" in the industry! Persistent memory enables workers to play with massive data + high-dimensional models
【应用推荐】最近大火的Apifox & Apipost 上手体验与选型建议
How to easily realize online karaoke room and sing "mountain sea" with Wang Xinling
随机推荐
60 divine vs Code plug-ins!!
【Prometheus】2. Overview and deployment
Web page live broadcast on demand RTMP streaming platform easydss newly added virtual live broadcast support dash streaming function
Global and Chinese market of training dance clothes 2022-2028: Research Report on technology, participants, trends, market size and share
Goby+AWVS 实现攻击面检测
#夏日挑战赛# HarmonyOS - 实现带日期效果的待办事项
Introduction to new features of ECMAScript 2019 (ES10)
Goby+awvs realize attack surface detection
Golang+redis distributed mutex
Istio FAQ: sidecar stop sequence
2021-04-28: force buckle 546, remove the box. Give some boxes of different colors
Install the imagemagick7.1 library and the imageick extension for PHP
C. K-th not divisible by n (Mathematics + thinking) codeforces round 640 (Div. 4)
It may be a good idea to use simulation software in the cloud for simulation
Some experiences of K project: global template highlights
Using alicloud RDS for SQL Server Performance insight to optimize database load - first understanding of performance insight
Global and Chinese market of inverted syrup 2022-2028: Research Report on technology, participants, trends, market size and share
Global and Chinese market for commercial barbecue smokers 2022-2028: Research Report on technology, participants, trends, market size and share
50 growers | closed door meeting of marketing circle of friends ス gathering Magic City thinking collision to help enterprise marketing growth
安裝ImageMagick7.1庫以及php的Imagick擴展