对象存储Minio 客户端工具类,实现文件上传、图像压缩、图像添加水印

在搭建好了MInio分布式对象存储集群后,官方提供了MInio Client 各类语言的SDK,但是无法直接使用需要进一步封装,这里将JAVA 版的的SDK结合自身业务做个简单封装。

Minio 中文文档入口:https://docs.min.io/cn/minio-quickstart-guide.html

Minio Clinet SDK文档入口:https://docs.min.io/cn/java-client-api-reference.html

以下共有俩个工具类,其中MioioUtil负责处理文件的上传及minio的相关初始化,ImageUtil负责对图像文件进行压缩及添加水印的操作。

需要在pom.xml中引入两个jar包:

MInio Client sdk包和谷歌的thumbnailator图像处理工具::

<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>3.0.10</version>
</dependency>
<dependency>
    <groupId>net.coobird</groupId>
    <artifactId>thumbnailator</artifactId>
    <version>0.4.8</version>
</dependency>
MinioUtil.class如下:
import io.minio.MinioClient;
import io.minio.errors.InvalidEndpointException;
import io.minio.errors.InvalidPortException;
import io.minio.policy.PolicyType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.io.InputStream;
import java.time.LocalDate;
import java.util.Random;

/**
 * 对象存储工具类
 * @author 10552
 */
public class MinioUtil {
    private static final Logger log = LoggerFactory.getLogger(MinioUtil.class);
    //Mino服务器的AccessKey
    private final transient static String ACCESS_KEY="填写你的Mino服务器AccessKey";
    //Mino服务器的SecretKey
    private final transient static String SECRET_KEY="填写你的Mino服务器SecretKey";
    //桶名称
    private final transient static String BUCKET_NAME="delivery";
    //读写分离-上传服务器
    private final transient static String OSS_URL_WRITE="http://你的服务器上传地址";
    //读写分离-下载服务器
    private final transient static String OOS_URL_READ="http://你的服务器下载地址";
    //minio服务端口,默认是9000
    private final transient static int OSS_PORT=9000;
    private transient static boolean BUCKET_EXISTS=false;
    //单例模式-内部类实现
    private static class MinioClientHolder {
        private static  MinioClient minioClient;
        static {
            try {
                minioClient = new MinioClient(OSS_URL_WRITE, OSS_PORT,ACCESS_KEY, SECRET_KEY);
            } catch (InvalidEndpointException e) {
                e.printStackTrace();
            } catch (InvalidPortException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 获取minio客户端实例
     * @return
     */
    private static MinioClient getMinioClient(){
        return MinioClientHolder.minioClient;
    }

    /**
     * 上传文件
     * 支持单文件,多文件
     * 返回文件访问路径,多文件以分号‘;’分隔
     * @param muFiles
     * @return
     */
    public static String uploadFiles(MultipartFile... muFiles) {
        if (muFiles.length<1){
            throw new RuntimeException("上传文件为空!");
        }
        StringBuilder str=new StringBuilder();
        for (MultipartFile muFile : muFiles) {
            str.append(uploadFile(muFile));
            str.append(";");
        }
        return str.deleteCharAt(str.length()-1).toString();

    }

    /**
     * 内部方法
     * 上传文件
     * @param muFile
     * @return
     */
    private static String uploadFile(MultipartFile muFile){
        String fileName = getFilePathName(muFile,false);
        try {
            MinioClient minioClient = getMinioClient();
            if(!BUCKET_EXISTS&&!minioClient.bucketExists(BUCKET_NAME)){
                minioClient.makeBucket(BUCKET_NAME);
                minioClient.setBucketPolicy(BUCKET_NAME, "", PolicyType.READ_ONLY);
                BUCKET_EXISTS=true;
            }
            InputStream inputStream=muFile.getInputStream();
            //如果是图片文件就进行压缩
            if (ImageUtil.isImage(muFile.getOriginalFilename())){
                inputStream=ImageUtil.getInputStream(
                        ImageUtil.setWatermark(
                                ImageUtil.compress(
                                        ImageIO.read(inputStream))),
                        ImageUtil.getFileExtention(muFile.getOriginalFilename()));
            }
            minioClient.putObject(BUCKET_NAME, fileName , inputStream,muFile.getContentType());
        }  catch (Exception e) {
            log.error("文件上传失败",e);
            throw new RuntimeException("文件上传失败");
        }
        return OOS_URL_READ+BUCKET_NAME+fileName;
    }

    /**
     * 	 获取文件名
     * @param muFile 文件
     * @param isRetain 是否保留源文件名
     * @return 返回文件名,以当前年月日作为前缀路径
     */
    private static String getFilePathName(MultipartFile muFile,boolean isRetain){
        String fileName = muFile.getOriginalFilename();
        String name=fileName;
        String prefix="";
        if(fileName.indexOf('.')!=-1) {
            name=fileName.substring(0,fileName.indexOf('.'));
            prefix=fileName.substring(fileName.lastIndexOf("."));
        }

        LocalDate date = LocalDate.now();
        StringBuilder filePathName=new StringBuilder("/upload/");
        filePathName.append(date.getYear());
        filePathName.append("/");
        filePathName.append(date.getMonthValue());
        filePathName.append("/");
        filePathName.append(date.getDayOfMonth());
        filePathName.append("/");
        //添加随机后缀
        Random r = new Random();
        int pix=r.ints(1, (100 + 1)).findFirst().getAsInt();
        filePathName.append(System.currentTimeMillis());
        filePathName.append(""+pix);
        //文件名超过32字符则截取
        if(isRetain){
            filePathName.append("_");
            if(name.length()>=32){
                name=name.substring(0,32);
            }
            filePathName.append(name);
        }
        filePathName.append(prefix);
        return filePathName.toString();
    }

ImageUtil.class工具类如下:

import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.geometry.Positions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.font.TextAttribute;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;

/**
 * 图像工具类
 */
public class ImageUtil {
    private static final Logger log = LoggerFactory.getLogger(ImageUtil.class);
    //压缩率
    private static final transient  float IMAGE_RATIO=0.1f;
    //压缩最大宽度
    private static final transient  int IMAGE_WIDTH=800;
    // 水印透明度
    private static float alpha = 0.3f;
    // 水印文字字体
    private static Font font = new Font("PingFang SC Regular", Font.PLAIN, 36);
    // 水印文字颜色
    private static Color color = new Color(111, 111, 111);
    //水印文字内容
    private static final String text="这是一个水印文本";
    // 水印之间的间隔
    private static final int XMOVE = 80;
    // 水印之间的间隔
    private static final int YMOVE = 80;

    /**
     * 压缩图像
     * @param image
     * @return
     * @throws IOException
     */
    public static BufferedImage compress(BufferedImage image) throws IOException {
        Thumbnails.Builder<BufferedImage> imageBuilder= Thumbnails.of(image).outputQuality(IMAGE_RATIO);
        if(image.getWidth()>IMAGE_WIDTH){
            return imageBuilder.width(IMAGE_WIDTH).asBufferedImage();
        }
        else {
            return imageBuilder.scale(1).asBufferedImage();
        }
    }

    /**
     * 图像添加水印
     * @param
     * @return
     */
    public static BufferedImage setWatermark(BufferedImage image)throws IOException {
        return Thumbnails.of(image)
                .outputQuality(IMAGE_RATIO)
                .scale(1)
                .watermark(Positions.BOTTOM_RIGHT
                        ,createWatermark(text
                                ,image.getWidth()
                                ,image.getHeight()
                        )
                        ,alpha)
                .asBufferedImage();
    }
    /**
     * 根据文件扩展名判断文件是否图片格式
     * @return
     */
    public static boolean isImage(String fileName) {
        String[] imageExtension = new String[]{"jpeg", "jpg", "gif", "bmp", "png"};

        for (String e : imageExtension) if (getFileExtention(fileName).toLowerCase().equals(e)) return true;

        return false;
    }

    /**
     * 获取文件后缀名称
     * @param fileName
     * @return
     */
    public static String getFileExtention(String fileName) {
        String extension = fileName.substring(fileName.lastIndexOf(".") + 1);
        return extension;
    }
    /**
     * 根据图片对象获取对应InputStream
     *
     * @param image
     * @param readImageFormat
     * @return
     * @throws IOException
     */
    public static InputStream getInputStream(BufferedImage image, String readImageFormat) throws IOException
    {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        ImageIO.write(image, readImageFormat, os);
        InputStream is = new ByteArrayInputStream(os.toByteArray());
        os.close();
        return is;
    }
    /**
     * 创建水印图片
     * @param text 水印文字
     * @param width 图片宽
     * @param height 图片高
     * @return
     */
    public static BufferedImage createWatermark(String text,int width,int height)  {
        BufferedImage image = new BufferedImage(width
                , height, BufferedImage.TYPE_INT_RGB);
        // 2.获取图片画笔
        Graphics2D g = image.createGraphics();
        // ----------  增加下面的代码使得背景透明  -----------------
        image = g.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
        g.dispose();
        g = image.createGraphics();
        // ----------  背景透明代码结束  -----------------
        // 6、处理文字
        AttributedString ats = new AttributedString(text);
        ats.addAttribute(TextAttribute.FONT, font, 0, text.length());
        AttributedCharacterIterator iter = ats.getIterator();
        // 7、设置对线段的锯齿状边缘处理
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        // 8、设置水印旋转
        g.rotate(Math.toRadians(-30));
        // 9、设置水印文字颜色
        g.setColor(color);
        // 10、设置水印文字Font
        g.setFont(font);
        // 11、设置水印文字透明度
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha));
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
        /**
         * 水印铺满图片
         * 计算水印位置
         */
        int x = -width / 2;
        int y = -height / 2;
        int[] arr = getWidthAndHeight(text, font);
        int markWidth = arr[0];// 字体长度
        int markHeight = arr[1];// 字体高度
        // 循环添加水印
        while (x < width * 1.5) {
            y = -height / 2;
            while (y < height * 1.5) {
                g.drawString (text, x, y);

                y += markHeight + YMOVE;
            }
            x += markWidth + XMOVE;
        }
        // 13、释放资源
        g.dispose();
        return image;
    }

    /**
     * 计算字体宽度及高度
     * @param text
     * @param font
     * @return
     */
    private static int[] getWidthAndHeight(String text, Font font) {
        Rectangle2D r = font.getStringBounds(text, new FontRenderContext(
                AffineTransform.getScaleInstance(1, 1), false, false));
        int unitHeight = (int) Math.floor(r.getHeight());//
        // 获取整个str用了font样式的宽度这里用四舍五入后+1保证宽度绝对能容纳这个字符串作为图片的宽度
        int width = (int) Math.round(r.getWidth()) + 1;
        // 把单个字符的高度+3保证高度绝对能容纳字符串作为图片的高度
        int height = unitHeight + 3;
        return new int[]{width, height};
    }

 

 

迷你图片批量处理工具,她能够帮您迅速大批量处理您的图片。您只需要将一张或多张图片甚至一个文件夹拖放到添加窗口,即可完成图片添加,方便好用。 功能概述:批量更改大小、批量图片压缩、批量添加水印、批量更改格式、批量增特效等。 修订概述: 新增水印图片旋转功能。 新增图片旋转、灰色、反色、模糊、锐化、棕色、红色、绿色、蓝色、青色、品红、黄色等特效处理。 新增图片色相、饱和度、亮度、对比度、阀值等调整功能。 新增以文件名、拍摄时间、当前时间为水印文字的设置。 新增水印文字与水印图片的同时支持。 新增图片裁剪的自定义裁剪位置。 新增添加水印时对小尺寸图片的过滤功能。 新增设置保存功能。 新增水印图片输入框拖拽功能,您可以直接将水印图片拖拽至水印图片文本框。 修正了多文件夹拖拽到添加图片窗体后出现的程序崩溃问题。 修订了图片修改后EXIF信息丢失的问题。 新增图片列表Delete快捷键移除图片功能。 提示:如果您不能正常使用该软件,请安装.NET Framework 2.0, 下载地址:http://www.microsoft.com/downloads/details.aspx?familyid=0856EACB-4362-4B0D-8EDD-AAB15C5E04F5&displaylang=zh-cn 迷你软件系列工具: 迷你图片批量处理工具 迷你文件校验工具 迷你定时提醒工具 迷你词典(MiniDict) Excel数据导出工具 迷你网站检测工具 迷你批量更改文件编码工具 ... 、
Minio 是一个开源的云存储服务,它提供了一种简单的方法来存储和检索对象(如文件、图像等)。关于使用 Minio 压缩图片Java 中,你可以按照以下步骤操作: 1. 安装 Minio SDK for Java: 首先,你需要在项目中添加 MinioJava SDK 库,可以通过 Maven 或 Gradle 的依赖管理来完成。 2. 连接 Minio: 使用 SDK 创建连接到你的 Minio 存储实例的客户端,通常需要提供服务器地址、访问 key 和 secret key。 ```java import io.minio.MinioClient; import io.minio.errors.MinioException; // ... MinioClient client = new MinioClient("http://your-minio-server:9000", "your-access-key", "your-secret-key"); ``` 3. 图片上传: 在上传图片之前,可以使用 Java 的 ImageIO 工具对图片进行压缩。例如,你可以使用 `JPEGImageIO` 对 JPEG 格式的图片进行压缩: ```java import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.IOException; // ... try { BufferedImage image = ImageIO.read(new File("original.jpg")); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ImageIO.write(resizedImage, "jpg", outputStream); byte[] compressedImageBytes = outputStream.toByteArray(); // 然后使用 Minio 客户端上传压缩后的图片 client.putObject("bucket-name", "compressed-image.jpg", compressedImageBytes); } catch (IOException e) { e.printStackTrace(); } ``` 4. 压缩策略: Minio本身并不直接提供图片压缩功能,但你可以结合第三方库(如 Apache Commons Imaging 或者 OpenCV)来处理图片压缩,然后上传。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值