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,读取缩略图的BufferedImage
                BufferedImage 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;
    }

猜你喜欢

转载自blog.csdn.net/qq_61950936/article/details/143014881