当前位置: 首页 > news >正文

Java 通过GDAL实现将图片转成GEOTIFF文件

业务背景:

需要将图片文件转成带坐标的TIF文件

具体实现如下:

1️⃣GDAL方式

导入依赖包:

<!-- GDAL包引入 --> <dependency> <groupId>org.gdal</groupId> <artifactId>gdal</artifactId> <version>3.8.0</version> </dependency>

具体实现方法:

import org.gdal.gdal.*; import org.gdal.osr.SpatialReference; import org.springframework.web.multipart.MultipartFile; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.awt.image.DataBufferByte;

方法代码:

/** * 创建 geo tiff 流 * * @param file 文件 * @param outputTiff 输出 TIFF * @param topLeftX 左上角 * @param topLeftY 左上角 * @param topRightX 右上角 * @param topRightY 右上角 * @param bottomRightX 右下角 * @param bottomRightY 右下角 * @param epsg EPSG */ public void createGeoTiffStream( MultipartFile file, String outputTiff, double topLeftX, double topLeftY, double topRightX, double topRightY, double bottomRightX, double bottomRightY, int epsg ) { try { // ============================ // 1. MultipartFile → Image // ============================ BufferedImage img = ImageIO.read(file.getInputStream()); if (img == null) { throw new IllegalArgumentException("无法读取上传的图片文件"); } // 强制为 TYPE_3BYTE_BGR(最快) if (img.getType() != BufferedImage.TYPE_3BYTE_BGR) { BufferedImage converted = new BufferedImage( img.getWidth(), img.getHeight(), BufferedImage.TYPE_3BYTE_BGR ); Graphics2D g = converted.createGraphics(); g.drawImage(img, 0, 0, null); g.dispose(); img = converted; } int w = img.getWidth(); int h = img.getHeight(); // ============================ // 2. GeoTransform 计算 // ============================ double pixelWidth = (topRightX - topLeftX) / w; double pixelHeight = (bottomRightY - topLeftY) / h; pixelHeight = -Math.abs(pixelHeight); // Y 方向必须为负 double[] geo = new double[]{ topLeftX, pixelWidth, 0, topLeftY, 0, pixelHeight }; SpatialReference srs = new SpatialReference(); srs.ImportFromEPSG(epsg); // ============================ // 3. 创建 GeoTIFF(最高速) // ============================ Driver driver = gdal.GetDriverByName("GTiff"); Dataset ds = driver.Create( outputTiff, w, h, 3, gdalconstConstants.GDT_Byte, new String[]{ "COMPRESS=NONE", "TILED=NO" } ); ds.SetGeoTransform(geo); ds.SetProjection(srs.ExportToWkt()); // ============================ // 4. 高速拆分 RGB 通道 // ============================ byte[] pixels = ((DataBufferByte) img.getRaster().getDataBuffer()).getData(); int size = w * h; byte[] r = new byte[size]; byte[] gArr = new byte[size]; byte[] b = new byte[size]; for (int i = 0, p = 0; i < size; i++) { b[i] = pixels[p++]; // B gArr[i] = pixels[p++]; // G r[i] = pixels[p++]; // R } // ============================ // 5. 写入 Raster(一次写入) // ============================ ds.GetRasterBand(1).WriteRaster(0, 0, w, h, r); ds.GetRasterBand(2).WriteRaster(0, 0, w, h, gArr); ds.GetRasterBand(3).WriteRaster(0, 0, w, h, b); // 完成 ds.FlushCache(); ds.delete(); } catch (Exception e) { throw new RuntimeException("生成 GeoTIFF 失败", e); } } // 如果是文件地址,可以使用如下方法 /** * 创建geo tiff路径 * * @param srcImagePath SRC图像路径 * @param outputTiff 输出 TIFF * @param topLeftX 左上角 * @param topLeftY 左上角 * @param topRightX 右上角 * @param topRightY 右上角 * @param bottomRightX 右下角 * @param bottomRightY 右下角 * @param epsg EPSG */ public void createGeoTiffPath( String srcImagePath, String outputTiff, double topLeftX, double topLeftY, double topRightX, double topRightY, double bottomRightX, double bottomRightY, int epsg ) { try { // ============================ // 1. MultipartFile → Image // ============================ //BufferedImage img = ImageIO.read(file.getInputStream()); BufferedImage img = ImageIO.read(new File(srcImagePath)); if (img == null) { throw new IllegalArgumentException("无法读取上传的图片文件"); } // 强制为 TYPE_3BYTE_BGR(最快) if (img.getType() != BufferedImage.TYPE_3BYTE_BGR) { BufferedImage converted = new BufferedImage( img.getWidth(), img.getHeight(), BufferedImage.TYPE_3BYTE_BGR ); Graphics2D g = converted.createGraphics(); g.drawImage(img, 0, 0, null); g.dispose(); img = converted; } int w = img.getWidth(); int h = img.getHeight(); // ============================ // 2. GeoTransform 计算 // ============================ double pixelWidth = (topRightX - topLeftX) / w; double pixelHeight = (bottomRightY - topLeftY) / h; pixelHeight = -Math.abs(pixelHeight); // Y 方向必须为负 double[] geo = new double[]{ topLeftX, pixelWidth, 0, topLeftY, 0, pixelHeight }; SpatialReference srs = new SpatialReference(); srs.ImportFromEPSG(epsg); // ============================ // 3. 创建 GeoTIFF(最高速) // ============================ Driver driver = gdal.GetDriverByName("GTiff"); Dataset ds = driver.Create( outputTiff, w, h, 3, gdalconstConstants.GDT_Byte, new String[]{ "COMPRESS=NONE", "TILED=NO" } ); ds.SetGeoTransform(geo); ds.SetProjection(srs.ExportToWkt()); // ============================ // 4. 高速拆分 RGB 通道 // ============================ byte[] pixels = ((DataBufferByte) img.getRaster().getDataBuffer()).getData(); int size = w * h; byte[] r = new byte[size]; byte[] gArr = new byte[size]; byte[] b = new byte[size]; for (int i = 0, p = 0; i < size; i++) { b[i] = pixels[p++]; // B gArr[i] = pixels[p++]; // G r[i] = pixels[p++]; // R } // ============================ // 5. 写入 Raster(一次写入) // ============================ ds.GetRasterBand(1).WriteRaster(0, 0, w, h, r); ds.GetRasterBand(2).WriteRaster(0, 0, w, h, gArr); ds.GetRasterBand(3).WriteRaster(0, 0, w, h, b); // 完成 ds.FlushCache(); ds.delete(); } catch (Exception e) { throw new RuntimeException("生成 GeoTIFF 失败", e); } }

2️⃣其他方式(如:geotools方式等)

导入依赖

<!-- GeoTools包引入 <geotools.version>25.1</geotools.version> --> <dependency> <groupId>org.geotools</groupId> <artifactId>gt-swing</artifactId> <version>${geotools.version}</version> </dependency> <dependency> <groupId>org.geotools</groupId> <artifactId>gt-geojson</artifactId> <version>${geotools.version}</version> </dependency> <dependency> <groupId>org.geotools</groupId> <artifactId>gt-geotiff</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-referencing</artifactId> <version>28.2</version> </dependency>

具体实现方法:

import org.geotools.coverage.grid.GridCoverage2D; import org.geotools.coverage.grid.GridCoverageFactory; import org.geotools.gce.geotiff.GeoTiffWriter; import org.geotools.geometry.GeneralEnvelope; import org.geotools.referencing.CRS; import org.opengis.referencing.FactoryException; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.TransformException; import org.springframework.web.multipart.MultipartFile; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; /** * Geo TIFF Utils * * @author ATB */ public class GeoTiffUtils { /** * 将前端上传的 PNG 文件写入 GeoTIFF * * @param file MultipartFile PNG 文件 * @param tiffFilePath 输出 GeoTIFF 文件路径 * @param minX 左下角 X 坐标 * @param minY 左下角 Y 坐标 * @param maxX 右上角 X 坐标 * @param maxY 右上角 Y 坐标 * @param epsg EPSG 投影,例如 4326 */ public static void writePngToGeoTiff(MultipartFile file, String tiffFilePath, double minX, double minY, double maxX, double maxY, int epsg) throws IOException, TransformException, FactoryException { // 从 MultipartFile 读取 BufferedImage BufferedImage image = ImageIO.read(file.getInputStream()); if (image == null) { throw new IOException("无法读取 PNG 文件: " + file.getOriginalFilename()); } // 创建坐标范围 GeneralEnvelope envelope = new GeneralEnvelope(2); envelope.setRange(0, minX, maxX); // X 轴 envelope.setRange(1, minY, maxY); // Y 轴 // 坐标参考系 CoordinateReferenceSystem crs = CRS.decode("EPSG:" + epsg); envelope.setCoordinateReferenceSystem(crs); // 创建 GridCoverage2D 对象 GridCoverageFactory factory = new GridCoverageFactory(); GridCoverage2D coverage = factory.create("coverage", image, envelope); // 写入 GeoTIFF File tiffFile = new File(tiffFilePath); GeoTiffWriter writer = new GeoTiffWriter(tiffFile); writer.write(coverage, null); writer.dispose(); } /** * 将 PNG 图像写入 GeoTIFF * * @param pngFilePath PNG 文件路径 * @param tiffFilePath 输出 GeoTIFF 文件路径 * @param minX 左下角 X 坐标 * @param minY 左下角 Y 坐标 * @param maxX 右上角 X 坐标 * @param maxY 右上角 Y 坐标 * @param epsg EPSG 投影,例如 4326 */ public static void writePngToGeoTiff(String pngFilePath, String tiffFilePath, double minX, double minY, double maxX, double maxY, int epsg) throws IOException, TransformException, FactoryException { // 读取 PNG 图片 BufferedImage image = ImageIO.read(new File(pngFilePath)); if (image == null) { throw new IOException("无法读取 PNG 文件: " + pngFilePath); } int width = image.getWidth(); int height = image.getHeight(); // 设置坐标范围 GeneralEnvelope envelope = new GeneralEnvelope(2); envelope.setRange(0, minX, maxX); // X 轴 envelope.setRange(1, minY, maxY); // Y 轴 // 坐标参考系 CoordinateReferenceSystem crs = CRS.decode("EPSG:" + epsg); envelope.setCoordinateReferenceSystem(crs); // 创建 GridCoverage2D 对象 GridCoverageFactory factory = new GridCoverageFactory(); GridCoverage2D coverage = factory.create("coverage", image, envelope); // 写入 GeoTIFF File tiffFile = new File(tiffFilePath); GeoTiffWriter writer = new GeoTiffWriter(tiffFile); writer.write(coverage, null); writer.dispose(); } }

好了,至此就可以实现将图片文件转成GEOTIFF文件了(同时至此文件路径和文件流方式)!

http://www.jsqmd.com/news/436292/

相关文章:

  • 聚焦环保全屋定制:2026国内最新适配家装柜体防潮需求的十大木纹板材实力厂家 - 十大品牌榜
  • 基于深度学习的苹果成熟度识别检测系统|全新web界面|多模态|AI大模型智能分析|YOLOv8、YOLOv10、YOLOv11、YOLOv12
  • 车载以太网设备如何进行线束连接
  • 靠谱的海关数据生产厂家
  • 聚焦环保健康全屋定制:2026国内最新适配家装柜体需求的十大生态板加工厂 - 十大品牌榜
  • 基于深度学习的条形码识别检测系统|全新web界面|多模态|AI大模型智能分析|YOLOv8、YOLOv10、YOLOv11、YOLOv12
  • Matlab直流潮流程序实现详解(基于IEEE 9节点系统)
  • winform 继承Panel的控件设置双缓冲
  • 基于深度学习的轴承缺陷识别检测系统|全新web界面|多模态|AI大模型智能分析|YOLOv8、YOLOv10、YOLOv11、YOLOv12
  • 内燃机专业EI会议IOP-JPCS出版 | 2026年内燃机技术与能源动力工程国际学术会议(ICTEPE 2026)
  • Java基础(下)之网络编程
  • 聚焦环保健康全屋定制:2026国内最新适配家装全场景的十大柜子定制板材生产厂家 - 十大品牌榜
  • Java基础(课后笔记)
  • 改造策略
  • Superpowers:CC 资深工程素养 Skills 库
  • CANoe性能问题的处理方法
  • GIT将某分支(develop分支)合并至某分支(yunwei/develop分支)具体过程
  • 2026年发电机租赁行业权威分析报告:深度解析与优选指南 - 深度智识库
  • C++数据结构与算法_双指针法
  • 2026年中国智能办公平台深度研究报告
  • 【奖励到账】CSDN AI 社区镜像创作激励活动第八批奖励正式发放!
  • 聚焦环保全屋定制:2026国内最新适配家装柜体需求的十大欧松板源头厂家 - 十大品牌榜
  • 2026年发电车租赁厂家三大推荐榜:发电车租赁行业现状与筛选标准 - 深度智识库
  • Xbotics社区 | ArXiv 机器人学每日速递(2026.03.04)
  • 氙灯老化试验箱2026行业全景探究:六大主流品牌厂家实力剖析与科学选型指南 - 品牌推荐大师1
  • 国内有哪些好的字画回收机构?科普指南教你精准挑选 - 品牌排行榜单
  • BXMya GDD471A001 2UBA002322R0001 数字量输入/输出模块
  • 基于深度学习的工地运输车类型识别检测系统|全新web界面|多模态|AI大模型智能分析|YOLOv8、YOLOv10、YOLOv11、YOLOv12
  • 在 Windows 系统上一键安装 Ollama 的命令
  • 2026年 富锌漆厂家推荐排行榜:环氧/水性/无机富锌底漆,防腐防锈漆源头实力品牌深度解析 - 品牌企业推荐师(官方)