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

springboot使用GDAL获取tif文件的缩略图并转为base64

springboot使用GDAL获取tif文件的缩略图并转为base64

首先需要安装gdal:https://blog.csdn.net/qq_61950936/article/details/142880279?spm=1001.2014.3001.5501
然后是配置pom.xml文件:

		<!--处理缩略图的--><dependency><groupId>org.gdal</groupId><artifactId>gdal</artifactId><version>3.9.0</version></dependency>

更新maven。

效果:
在这里插入图片描述

TiffThumbnailGenerator类:

package com.geofly.dataservicecenter.api.common.util;import java.awt.*;import org.gdal.gdal.Dataset;
import org.gdal.gdal.gdal;
import org.gdal.gdal.Band;
import org.gdal.gdalconst.gdalconstConstants;import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.io.*;
import java.util.Base64;/*** @Description: 读取 tif文件的InputStream 并生成缩略图** @Auther: yanghaoxing* @Date: 2024/10/12*/
public class TiffThumbnailGenerator {static {System.loadLibrary("gdal");gdal.AllRegister();}// 将 InputStream 写入临时文件private static File inputStreamToFile(InputStream inputStream) throws IOException {File tempFile = File.createTempFile("tempTiff", ".tif");try (FileOutputStream out = new FileOutputStream(tempFile)) {byte[] buffer = new byte[1024];int bytesRead;while ((bytesRead = inputStream.read(buffer)) != -1) {out.write(buffer, 0, bytesRead);}}return tempFile;}/*** @Description: 传入InputStream,读取缩略图的BufferedImage** @Param:  [inputStream, width, height]* @Return: java.awt.image.BufferedImage* @Author yanghaoxing* @Date 2024/10/12 16:25*/public static BufferedImage generateThumbnail(InputStream inputStream, int width, int height) throws IOException {File tiffFile = inputStreamToFile(inputStream);Dataset dataset = gdal.Open(tiffFile.getAbsolutePath(), gdalconstConstants.GA_ReadOnly);if (dataset == null) {// 无法打开 TIFF 文件return null;}int xSize = dataset.getRasterXSize();int ySize = dataset.getRasterYSize();// 读取三个波段(假设分别为 R、G、B)Band bandRed = dataset.GetRasterBand(1);  // 红波段Band bandGreen = dataset.GetRasterBand(2);  // 绿波段Band bandBlue = dataset.GetRasterBand(3);  // 蓝波段// 分配数组来存储波段数据int[] redData = new int[xSize * ySize];int[] greenData = new int[xSize * ySize];int[] blueData = new int[xSize * ySize];// 读取波段数据bandRed.ReadRaster(0, 0, xSize, ySize, redData);bandGreen.ReadRaster(0, 0, xSize, ySize, greenData);bandBlue.ReadRaster(0, 0, xSize, ySize, blueData);// 创建 RGB 图像BufferedImage originalImage = new BufferedImage(xSize, ySize, BufferedImage.TYPE_INT_RGB);for (int y = 0; y < ySize; y++) {for (int x = 0; x < xSize; x++) {int r = redData[y * xSize + x];int g = greenData[y * xSize + x];int b = blueData[y * xSize + x];int rgb = (r << 16) | (g << 8) | b;originalImage.setRGB(x, y, rgb);}}// 先裁剪掉黑边BufferedImage croppedImage = cropBlackBorders(originalImage);// 然后缩放并居中图像BufferedImage resizedImage = resizeAndCenterImage(croppedImage, width, height);// 关闭数据集dataset.delete();return resizedImage;}// 缩放图片以适应指定大小并保持宽高比public static BufferedImage resizeAndCenterImage(BufferedImage originalImage, int targetWidth, int targetHeight) {int originalWidth = originalImage.getWidth();int originalHeight = originalImage.getHeight();// 计算缩放比例,保持宽高比double scaleFactor = Math.min((double) targetWidth / originalWidth, (double) targetHeight / originalHeight);int scaledWidth = (int) (originalWidth * scaleFactor);int scaledHeight = (int) (originalHeight * scaleFactor);// 创建一个新的目标图像(透明背景)BufferedImage resizedImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_ARGB);// 在新图像上进行绘制Graphics2D g2d = resizedImage.createGraphics();g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);// 计算居中位置int x = (targetWidth - scaledWidth) / 2;int y = (targetHeight - scaledHeight) / 2;// 填充透明背景并绘制缩放后的图像g2d.drawImage(originalImage, x, y, scaledWidth, scaledHeight, null);g2d.dispose();return resizedImage;}// 裁剪黑边(裁剪掉纯黑的区域)public static BufferedImage cropBlackBorders(BufferedImage image) {int width = image.getWidth();int height = image.getHeight();int top = 0, bottom = height - 1, left = 0, right = width - 1;boolean foundTop = false, foundBottom = false, foundLeft = false, foundRight = false;// 检测上边界for (int y = 0; y < height && !foundTop; y++) {for (int x = 0; x < width; x++) {if (!isBlack(image.getRGB(x, y))) {top = y;foundTop = true;break;}}}// 检测下边界for (int y = height - 1; y >= 0 && !foundBottom; y--) {for (int x = 0; x < width; x++) {if (!isBlack(image.getRGB(x, y))) {bottom = y;foundBottom = true;break;}}}// 检测左边界for (int x = 0; x < width && !foundLeft; x++) {for (int y = 0; y < height; y++) {if (!isBlack(image.getRGB(x, y))) {left = x;foundLeft = true;break;}}}// 检测右边界for (int x = width - 1; x >= 0 && !foundRight; x--) {for (int y = 0; y < height; y++) {if (!isBlack(image.getRGB(x, y))) {right = x;foundRight = true;break;}}}// 裁剪图像return image.getSubimage(left, top, right - left + 1, bottom - top + 1);}// 判断一个像素是否是黑色(你可以根据需要调整黑色的判断标准)private static boolean isBlack(int rgb) {Color color = new Color(rgb);// 理论上应该是:color.getRed() == 0 && color.getGreen() == 0 && color.getBlue() == 0; 但是目前测试数据的黑边是色值是:1,1,0// 白边也去掉return (color.getRed() == 1 && color.getGreen() == 1 && color.getBlue() == 0) ||(color.getRed() == 0 && color.getGreen() == 0 && color.getBlue() == 0) ||(color.getRed() == 255 && color.getGreen() == 255 && color.getBlue() == 255);}// 将 BufferedImage 转换为 Base64 字符串public static String bufferedImageToBase64(BufferedImage image, String format) throws IOException {if (image == null) {return null;}ByteArrayOutputStream outputStream = new ByteArrayOutputStream();ImageIO.write(image, format, outputStream);byte[] imageBytes = outputStream.toByteArray();String base64Image = Base64.getEncoder().encodeToString(imageBytes);outputStream.close();return base64Image;}/*** @Description: 将BufferedImage写入指定路径** @Param:  [thumbnail, outputFilePath]* @Return: void* @Author yanghaoxing* @Date 2024/10/12 16:24*/public static void saveThumbnailToFile(BufferedImage thumbnail, String outputFilePath) throws IOException {File outputfile = new File(outputFilePath);ImageIO.write(thumbnail, "png", outputfile);}
}

使用:

/*** @Description: 根据文件id获取该tif图的缩略图** @Param:  [fileId]* @Return: String base64Image* @Author yanghaoxing* @Date 2024/10/12 10:24*/private String getTiffImageBuffered(List<String> fileIds) {int width = 255, height = 255;FileDownloadVo fileDownloadVo = uploadService.getFile(fileIds.get(0));if (fileDownloadVo != null && fileDownloadVo.getFileStream() != null) {InputStream inputStream = fileDownloadVo.getFileStream();try {// 传入InputStream,读取缩略图的BufferedImageBufferedImage bufferedImage = TiffThumbnailGenerator.generateThumbnail(inputStream, width, height);// 转为base64格式String base64Image = TiffThumbnailGenerator.bufferedImageToBase64(bufferedImage, "png");return base64Image != null ? "data:image/png;base64," + base64Image : null;} catch (IOException e) {return null;}}return null;}

相关文章:

springboot使用GDAL获取tif文件的缩略图并转为base64

springboot使用GDAL获取tif文件的缩略图并转为base64 首先需要安装gdal&#xff1a;https://blog.csdn.net/qq_61950936/article/details/142880279?spm1001.2014.3001.5501 然后是配置pom.xml文件&#xff1a; <!--处理缩略图的--><dependency><groupId>o…...

Pytorch——pip下载安装pytorch慢的解决办法

一、找到需要下载的pytorch链接 运行&#xff1a;pip install torch1.11.0cu113 torchvision0.12.0cu113 torchaudio0.11.0 --extra-index-url https://download.pytorch.org/whl/cu113。然后得到&#xff1a; 我这里为&#xff1a;https://download.pytorch.org/whl/cu113/t…...

uniapp微信小程序调用百度OCR

uniapp编写微信小程序调用百度OCR 公司有一个识别行驶证需求&#xff0c;调用百度ocr识别 使用了image-tools这个插件&#xff0c;因为百度ocr接口用图片的base64 这里只是简单演示&#xff0c;accesstoken获取接口还是要放在服务器端&#xff0c;不然就暴露了自己的百度项目k…...

Vue3+TS项目---实用的复杂类型定义总结

namespace 概念 在TypeScript中&#xff0c;namespace是一种用于组织代码得结构&#xff0c;主要用于将相关得功能&#xff08;例如类、接口、函数等&#xff09;组合在一起。它可以帮助避免命名冲突&#xff0c;尤其是在大项目中。 用法 1.定义命名空间 使用namespace关键…...

尚硅谷rabbitmq2024 工作模式路由篇 第11节 答疑

String exchangeName "test_direct"; /! 创建交换机 人图全 channel.exchangeDeclare(exchangeName,BuiltinExchangeType.DIREcT, b: true, b1: false, b2: false, map: null); /1 创建队列 String queue1Name "test_direct_queue1"; String queue2Name &q…...

HTTP vs WebSocket

本文将对比介绍HTTP 和 WebSocket &#xff01; 相关文章&#xff1a; 1.HTTP 详解 2.WebSocket 详解 一、HTTP&#xff1a;请求/响应的主流协议 HTTP&#xff08;超文本传输协议&#xff09;是用于发送和接收网页数据的标准协议。它最早于1991年由Tim Berners-Lee提出来&…...

R语言医学数据分析实践-数据读写

【图书推荐】《R语言医学数据分析实践》-CSDN博客 《R语言医学数据分析实践 李丹 宋立桓 蔡伟祺 清华大学出版社9787302673484》【摘要 书评 试读】- 京东图书 (jd.com) R语言编程_夏天又到了的博客-CSDN博客 R编程环境的搭建-CSDN博客 在分析公共卫生数据时&#xff0c;数…...

JavaWeb环境下Spring Boot在线考试系统的优化策略

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了基于JavaWeb技术的在线考试系统设计与实现的开发全过程。通过分析基于Java Web技术的在线考试系统设计与实现管理的不足&#xff0c;创建了一个计算机管理基于Ja…...

ETL技术在金蝶云星空与旺店通WMS集成中的应用

金蝶云星空数据集成到旺店通WMS的技术案例分享 在数字化转型的背景下&#xff0c;现代企业对系统间的数据集成需求日益增加。本篇文章将以“组装入库>其他入库单-1”方案为例&#xff0c;详细解析如何通过轻易云数据集成平台&#xff0c;实现金蝶云星空与旺店通WMS之间的数…...

【力扣热题100】3194. 最小元素和最大元素的最小平均值【Java】

题目&#xff1a;3194.最小元素和最大元素的最小平均值 你有一个初始为空的浮点数数组 averages。另给你一个包含 n 个整数的数组 nums&#xff0c;其中 n 为偶数。 你需要重复以下步骤 n / 2 次&#xff1a; 从 nums 中移除 最小 的元素 minElement 和 最大 的元素 maxElement…...

机器学习拟合过程

import numpy as np import matplotlib.pyplot as plt# 步骤1: 生成模拟数据 np.random.seed(0) X 2 * np.random.rand(100, 1) y 4 3 * X 2 * X**2 np.random.randn(100, 1)# 步骤2: 定义线性模型 (我们从随机权重开始) w np.random.randn(2, 1) b np.random.randn(1)#…...

如何快速部署一套智能化openGauss测试环境

一、openGauss介绍 openGauss是一款开源关系型数据库管理系统&#xff0c;采用木兰宽松许可证v2发行&#xff0c;允许用户自由地复制、使用、修改和分发软件。openGauss内核深度融合了华为在数据库领域多年的研发经验&#xff0c;结合企业级场景需求&#xff0c;持续构建竞争力…...

【设计模式】深入理解Python中的原型设计模式

深入理解Python中的原型设计模式 在软件开发中&#xff0c;有时需要创建对象的过程非常复杂或者代价较高&#xff0c;而在同一类对象的实例之间有很多重复的属性。为了避免重复构造对象&#xff0c;提升性能和效率&#xff0c;原型设计模式&#xff08;Prototype Pattern&…...

Django CORS配置方案

参考 https://pypi.org/project/django-cors-headers/ 在setting.py中设置 INSTALLED_APPS [......corsheaders, #添加此行 ]MIDDLEWARE[......corsheaders.middleware.CorsMiddleware, #添加此行django.middleware.common.CommonMiddleware,#django.middleware.csrf.CsrfVi…...

2024年开放式耳机哪个牌子好?推荐最好的顶级开放式耳机品牌

在当下&#xff0c;开放式耳机逐渐成为众多消费者的新宠。与传统入耳式耳机相比&#xff0c;开放式耳机展现出诸多独特之处。它可以呈现出更清晰的音质效果&#xff0c;让用户有更美妙的听觉体验。在佩戴感上&#xff0c;开放式耳机更为舒适&#xff0c;不会给耳朵带来压迫感。…...

零基础读懂Stable Diffusion!

前言 一文搞懂Stable Diffusion是什么&#xff0c;怎么训练和使用&#xff0c;语义信息影响生成图片的过程。>>[][加入极市CV技术交流群&#xff0c;走在计算机视觉的最前沿] 前几个月AIGC可谓是大热了一把&#xff0c;各种高质量的生成图片层出不穷&#xff0c;而其中…...

Hash Join 和 Index Join工作原理和性能差异

在数据库查询中&#xff0c;Hash Join 和 Index Join 是两种常见的表连接策略。了解它们的工作原理和性能差异有助于设计高效的数据库查询。我们可以使用 Java 模拟这两种不同的连接方式&#xff0c;并进行性能对比。 1. Hash Join 和 Index Join 的概念&#xff1a; Hash Joi…...

Apifox简介及使用

Apifox 是一款集 API文档管理、接口调试、接口自动化测试 和 Mock 功能于一体的全功能工具&#xff0c;旨在为开发者和测试人员提供一个高效的一站式解决方案。它融合了 Postman、Swagger、JMeter 等工具的优势&#xff0c;能够极大地提升团队协作和 API 开发的效率。 在实际开…...

十、IPD 实施细节(产品设计与开发管理)

产品设计与开发管理 产品设计与开发管理是IPD(集成产品开发)实施过程中的核心环节。它确保从概念设计到最终产品的实现能够按照预定的质量、成本、进度目标顺利完成,并与市场需求、技术发展及企业战略保持一致。IPD强调产品设计与开发管理过程中跨职能团队的协作、流程的系…...

MySQL-13.DQL-聚合函数

一.DQL-分组查询 二.聚合函数 -- DQL:分组查询 -- 聚合函数 -- 1.统计该企业员工数量 count select count(id) from tb_emp; select count(job) from tb_emp;select count(A) from tb_emp; select count(*) from tb_emp;-- 2.统计该企业最早入职的员工 min select min(entr…...

开源能源管理实战指南:从零开始掌握OpenEMS系统应用

开源能源管理实战指南&#xff1a;从零开始掌握OpenEMS系统应用 【免费下载链接】openems OpenEMS - Open Source Energy Management System 项目地址: https://gitcode.com/gh_mirrors/op/openems OpenEMS&#xff08;开源能源管理系统&#xff09;作为一款模块化的能源…...

webflux接收application/x-www-form-urlencoded参数

记录开发中遇到的问题 请求方式&#xff1a;需要用如下方式接收&#xff1a; 方式1PostMapping(value "/user/logout", consumes "application/x-www-form-urlencoded")public ResponseResult logoutForAuthSystem(ServerWebExchange exchange) {exchang…...

cf1091div2 C.Grid Covering(数论)

Problem - C - Codeforces 保证遍历完每行每列所以gcd(n,a)1,gcd(m,b)1很好理解 为了遍历所有网格&#xff0c;因为在2*lcm(n,m)次数后会再次踏上轮回重复循环&#xff0c;此时访问了2*lcm(n,m)个格子&#xff0c;于是 2*lcm(n,m)>n*m&#xff0c;也就是2*lcm>gcd(n,m)*…...

破解网页资源提取难题:猫抓让视频音频下载效率提升10倍

破解网页资源提取难题&#xff1a;猫抓让视频音频下载效率提升10倍 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 网课视频无法保存、直播回放找不…...

Wan2.1模型实测:用TurboDiffusion快速生成电商产品展示视频

Wan2.1模型实测&#xff1a;用TurboDiffusion快速生成电商产品展示视频 1. 引言&#xff1a;当电商遇上秒级视频生成 想象一下这个场景&#xff1a;你是一家电商公司的运营&#xff0c;明天就要上架一款新产品&#xff0c;需要制作10个不同风格、不同角度的产品展示视频。按照…...

如何为数字创作者解决广色域显示器色彩失真问题?novideo_srgb的革新性精准色彩映射实践

如何为数字创作者解决广色域显示器色彩失真问题&#xff1f;novideo_srgb的革新性精准色彩映射实践 【免费下载链接】novideo_srgb Calibrate monitors to sRGB or other color spaces on NVIDIA GPUs, based on EDID data or ICC profiles 项目地址: https://gitcode.com/gh…...

3步构建企业级认证系统实战指南:从0到1搭建安全认证中心

3步构建企业级认证系统实战指南&#xff1a;从0到1搭建安全认证中心 【免费下载链接】oauth2-server spring boot (springboot 3) oauth2 server sso 单点登录 认证中心 JWT,独立部署,用户管理 客户端管理 项目地址: https://gitcode.com/gh_mirrors/oau/oauth2-server …...

设备资产管理系统 + 工业软件集成:打通数据孤岛,释放智能运维新价值

在工业数字化转型浪潮中&#xff0c;越来越多企业意识到单一系统难以支撑复杂的设备管理需求。设备资产管理系统与 ERP、MES、PLM 等工业软件的集成&#xff0c;正成为提升运维效率、降低成本、实现预测性维护的关键路径。本文以科普视角&#xff0c;解析集成的核心价值、典型应…...

**发散创新:Go语言中分片(Slice)的高级用法与实战技巧**在Go语言编程中,**slice(分片)** 是最常用

发散创新&#xff1a;Go语言中分片&#xff08;Slice&#xff09;的高级用法与实战技巧 在Go语言编程中&#xff0c;slice&#xff08;分片&#xff09; 是最常用、最灵活的数据结构之一。它不仅是数组的“智能包装器”&#xff0c;更是高效内存管理和性能优化的核心工具。本文…...

突破显卡性能瓶颈:NVIDIA Profile Inspector高级配置与性能优化指南

突破显卡性能瓶颈&#xff1a;NVIDIA Profile Inspector高级配置与性能优化指南 【免费下载链接】nvidiaProfileInspector 项目地址: https://gitcode.com/gh_mirrors/nv/nvidiaProfileInspector 当你在4K分辨率下运行3A大作时&#xff0c;是否遇到过画面撕裂与输入延迟…...