背景
在日常工作中,需要根据某个经纬度范围获取当前的瓦片数据,再输出成Tiff文件数据,并追加经纬度信息。
代码
1、下面是主程序
package com.sungrow.admin.service.impl;
import com.sungrow.admin.service.TiffService;
import com.sungrow.admin.util.WGSUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridCoverageFactory;
import org.geotools.coverage.grid.io.AbstractGridFormat;
import org.geotools.gce.geotiff.GeoTiffFormat;
import org.geotools.gce.geotiff.GeoTiffWriteParams;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.opengis.coverage.grid.GridCoverageWriter;
import org.opengis.parameter.GeneralParameterValue;
import org.opengis.parameter.ParameterValueGroup;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.imageio.ImageIO;
import javax.media.jai.TiledImage;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import static jdk.nashorn.internal.runtime.regexp.joni.Config.log;
@Slf4j
@Service
@RequiredArgsConstructor
public class TiffServiceImpl implements TiffService {
@Value("${system.google-images-path}")
private String googleSatellitePath;
private String image_ext = ".jpg";
@Override
public void tile2Tiff(String source, double left, double top, double right, double bottom) {
// 获取x、y的数字最大值和最小值
int[] minXY = WGSUtil.wgs_to_tile(left, top);
int[] maxXY = WGSUtil.wgs_to_tile(right, bottom);
int posi1x = minXY[0];
int posi1y = minXY[1];
int posi2x = maxXY[0];
int posi2y = maxXY[1];
int lenX = posi2x - posi1x + 1;
int lenY = posi2y - posi1y + 1;
BufferedImage image = null;
WritableRaster raster = null;
BufferedImage defaultImage = null;
try {
defaultImage = ImageIO.read(this.getDefaultSatelliteFile());
} catch (IOException e) {
log.error("读取默认卫星影像栅格图片失败,请检查文件是否存在");
return;
}
BufferedImage blank = new BufferedImage(lenX * 256, lenY * 256, BufferedImage.TYPE_3BYTE_BGR);
raster = blank.copyData(null);
// 循环获取图片并生成WritableRaster对象
for (int i = posi1x; i <= posi2x; i++) {
for (int j = posi1y; j <= posi2y; j++) {
try {
image = ImageIO.read(this.getSatelliteFile(i, j));
} catch (IOException e) {
image = defaultImage;
}
raster.setRect((i - posi1x) * 256, (j - posi1y) * 256, image.getRaster());
}
}
// 设置包围盒
ReferencedEnvelope envelope = new ReferencedEnvelope(left, right, bottom, top, DefaultGeographicCRS.WGS84);
// 创建网格
GridCoverageFactory factory = new GridCoverageFactory();
GridCoverage2D gridCoverage = factory.create("my_grid", raster, envelope);
// 创建tiff生成参数
GeoTiffFormat format = new GeoTiffFormat();
GeoTiffWriteParams wp = new GeoTiffWriteParams();
wp.setCompressionMode(GeoTiffWriteParams.MODE_EXPLICIT);
wp.setCompressionType("Deflate");
ParameterValueGroup params = format.getWriteParameters();
params.parameter(AbstractGridFormat.GEOTOOLS_WRITE_PARAMS.getName().toString()).setValue(wp);
GeneralParameterValue[] writeParameters = params.values().toArray(new GeneralParameterValue[1]);
// gridCoverage
GeoTiffFormat format1 = new GeoTiffFormat();
File out = new File("D:\\123.tiff");
GridCoverageWriter writer = format1.getWriter(out);
try {
writer.write(gridCoverage, writeParameters);
writer.dispose();
} catch (IOException e) {
log.error("生成tiff失败:{}", e.getMessage());
}
gridCoverage.dispose(true);
}
/**
* 获取卫星影像图片
*
* @param x
* @param y
* @return
*/
private File getSatelliteFile(int x, int y) {
return new File(this.googleSatellitePath + 18 + File.separator + x + File.separator + y + this.image_ext);
}
/**
* 获取默认的卫星影像图片
*
* @return
*/
private File getDefaultSatelliteFile() {
return new File(this.googleSatellitePath + File.separator + "default_satellite" + this.image_ext);
}
}
2、下面是工具转换操作
package com.sungrow.admin.util;
public class WGSUtil {
/**
* wgs转tile,zoom按照默认18层级
*
* @param j 经度
* @param w 纬度
* @return
*/
public static int[] wgs_to_tile(double j, double w) {
if (j < 0) {
j = 180 + j;
} else {
j += 180;
}
j /= 360;
w = Math.min(w, 85.0511287798);
w = Math.max(w, -85.0511287798);
w = Math.log(Math.tan((90 + w) * Math.PI / 360)) / (Math.PI / 180);
w /= 180;
w = 1 - (w + 1) / 2;
int num = (int) Math.pow(2, 18);
int x = (int) Math.floor(j * num);
int y = (int) Math.floor(w * num);
return new int[]{x, y};
}
}
3、引入
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<geotools.version>27.0</geotools.version>
</properties>
<!--geoTools-->
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-jdbc</artifactId>
<version>${geotools.version}</version>
<exclusions>
<exclusion>
<artifactId>commons-collections</artifactId>
<groupId>commons-collections</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- <dependency>
<groupId>org.postgis</groupId>
<artifactId>postgis-jdbc</artifactId>
<version>${geotools.version}</version>
</dependency>-->
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-cql</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-ysld</artifactId>
<version>${geotools.version}</version>
</dependency>
<!--操作shape文件-->
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-shapefile</artifactId>
<version>${geotools.version}</version>
</dependency>
<!--坐标系-->
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-epsg-hsql</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-epsg-extension</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-geojson</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools.jdbc</groupId>
<artifactId>gt-jdbc-postgis</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-swing</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-epsg-hsql</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-main</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-opengis</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-xml</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-referencing</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-geotiff</artifactId>
<version>${geotools.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.osgeo/proj4j 用于投影坐标转化 -->
<dependency>
<groupId>org.osgeo</groupId>
<artifactId>proj4j</artifactId>
<version>0.1.0</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-process</artifactId>
<version>${geotools.version}</version>
</dependency>
<dependency>
<groupId>org.geotools</groupId>
<artifactId>gt-process-feature</artifactId>
<version>${geotools.version}</version>
</dependency>