当前位置:网站首页>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();
}
}边栏推荐
- MySQL進階系列:鎖-InnoDB中鎖的情况
- Bitwise Operators
- MySQL Innodb和Myisam
- Some experiences of K project: global template highlights
- How to easily realize online karaoke room and sing "mountain sea" with Wang Xinling
- April 23, 2021: there are n cities in the TSP problem, and there is a distance between any two cities
- 60 divine vs Code plug-ins!!
- Understanding of deep separable convolution, block convolution, extended convolution, transposed convolution (deconvolution)
- Join in ABAP CDs
- #夏日挑战赛# HarmonyOS - 实现带日期效果的待办事项
猜你喜欢
![[download attached] installation and simple use of Chinese version of awvs](/img/3b/f26617383690c86edff465c9a1099e.png)
[download attached] installation and simple use of Chinese version of awvs

Problems encountered in the work of product manager

Several common DoS attacks

C. K-th Not Divisible by n(数学+思维) Codeforces Round #640 (Div. 4)
MySQL進階系列:鎖-InnoDB中鎖的情况

Cap: multiple attention mechanism, interesting fine-grained classification scheme | AAAI 2021

【面试高频题】难度 3/5,可直接构造的序列 DP 题
![[interview high frequency questions] sequential DP questions with difficulty of 3/5 and direct construction](/img/32/720ffa63a90cd5d37460face3fde38.png)
[interview high frequency questions] sequential DP questions with difficulty of 3/5 and direct construction

B. Ternary Sequence(思维+贪心)Codeforces Round #665 (Div. 2)

Build go command line program tool chain
随机推荐
#夏日挑战赛# HarmonyOS - 实现带日期效果的待办事项
MD5 verification based on stm32
The decline of China's product managers: starting from the nostalgia for jobs
嵌入式开发基础之线程间通信
2021-04-29: given an array arr, it represents a row of balloons with scores. One for each blow
D. Solve The Maze(思维+bfs)Codeforces Round #648 (Div. 2)
PyTorch中的转置卷积详解
Flink kubernetes application deployment
How to easily realize online karaoke room and sing "mountain sea" with Wang Xinling
Enterprise security attack surface analysis tool
2021-04-25: given an array arr and a positive number m, the
sql 多表更新数据非常慢
Transpose convolution explanation
2021-04-18: given a two-dimensional array matrix, the value in it is either 1 or 0,
It may be a good idea to use simulation software in the cloud for simulation
CDs view permission check
ThinkPHP 漏洞利用工具
[tke] analysis of CLB loopback in Intranet under IPVS forwarding mode
April 30, 2021: there are residential areas on a straight line, and the post office can only be built on residential areas. Given an ordered positive array arr
Cloud + community [play with Tencent cloud] video solicitation activity winners announced