java 图片不失真缩放,ico格式图片转换,透明图层,jar->exe

Java 图片缩放,转ico格式

Java 在转换图片格式为 ico 时 需要引入 image4j 的依赖,分享写好的源码和并通过exe4j 打包好的exe小程序。因为功能太少所以再引入 thumbnailator 的依赖缩放图片。

依赖

<!-- 引入依赖-->
    <dependency>
      <groupId>net.ifok.image</groupId>
      <artifactId>image4j</artifactId>
      <version>0.7.2</version>
    </dependency>
<!-- 缩放图片的工具类 -->
    <dependency>
      <groupId>net.coobird</groupId>
      <artifactId>thumbnailator</artifactId>
      <version>0.4.19</version>
    </dependency>

ico图标转换

ico图标可以存储单个图案、多尺寸、多色板的图标文件。通常作为标志,目前主流的浏览器都支持ICO图标,在浏览器的地址栏、标签及收藏夹上显示,也可以用来,个性化设置文件夹或者程序。图标有一套标准的大小和属性格式,且通常是小尺寸的。(16,32,48,64,128,256)
在这里插入图片描述

截图来自:https://github.com/imcdonagh/image4j,主要就4个API,读取与转换 BMP与ICO两种格式。

这里只说 ICO。因为 ImageIO.write(缓冲图, “格式”, 流); 可以直接处理输出bmp格式。

    @Test
    public void test01() {

//        图片读取路径
        String inputPath = "F://1.jpeg";
//        输出路径
        String outputPath = "F://0.ico";
        // 把需要关闭的流放在 try(  里 ){。。。
        try (
                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(inputPath));
                BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outputPath));
        ) {
            // 读取 图片
            BufferedImage img = ImageIO.read(bis);
            // 写出 图片
//            ICOEncoder.write(Arrays.asList(img), bos);
            ICOEncoder.write(Collections.singletonList(img), bos);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    // 其他格式jpg/jpeg/png/gif/bmp 写出图片 记得格式后缀与格式相同 jpg比较省空间
    ImageIO.write(img,"jpg", bos);

因为一般ico图标尺寸都在256以下,这个工具类最多也就转换300*300 的图标,所以需要进行图片的缩放操作。

Thumbnails缩放操作

主要的一些操作。

.of ( ) 文件路径 ,流 或者 缓存图片

.toFile( “D://xxx.jpg” ) 文件转存路径

.asBufferedImage() 返回缓存图片

.toOutputStream(os) 赋予输出流

.size( w, h ) 按指定大小调整,配值 .keepAspectRatio(false) 取消默认的比例变化,会变形

.scale(0.25f) 按比例缩放。

.sourceRegion(x, y, w, h) 裁剪,前两个参数可以用枚举类 Positions.

​ 这个在另一篇里用到了

.rotate(-90) 旋转 正数:顺时针 负数:逆时针

.watermark(位置,水印图,透明度) 加水印

.outputQuality(0.8f) 图片质量

.outputFormat(“png”) 转图片格式 ,鸡肋

这里简单使用一下

    @Test
    public void test02() {

//        图片读取路径
        String inputPath = "F://1.jpeg";
//        输出路径
        String outputPath = "F://1.ico";
        // 把需要关闭的流放在 try(  里 ){。。。
        try (
                BufferedInputStream bis = new BufferedInputStream(new FileInputStream(inputPath));
                BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outputPath));
        ) {
            // 读取 图片
            BufferedImage img = ImageIO.read(bis);
            //of( inputPath / img ) 都可以 
            img= Thumbnails.of(img).size(256, 256).keepAspectRatio(false).outputQuality(1f).asBufferedImage();
            // 写出 图片
            ICOEncoder.write(Collections.singletonList(img), bos);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

好了主要功能就这些,为了方便以后使用,把这些东西写成窗体应用,导入使用一个美化包 flatlaf

<!-- GUI窗体应用美化包 -->
    <dependency>
      <groupId>com.formdev</groupId>
      <artifactId>flatlaf</artifactId>
      <version>3.1</version>
    </dependency>
使用:
        //  初始化美化包。
        FlatLightLaf.installLafInfo();
        try {
//  设置美化包风格。
//    FlatDarkLaf()、FlatLightLaf()、
//    FlatDarculaLaf()、FlatIntelliJLaf()这四种对象风格
            UIManager.setLookAndFeel(new FlatLightLaf());
        } catch (Exception ex) {
            System.err.println("窗体美化包加载失败!!");
        }

窗体页面样式:

在这里插入图片描述

展开后:
在这里插入图片描述

//转存路径默认是桌面地址。
String homePath=FileSystemView.getFileSystemView().getHomeDirectory().getAbsolutePath();

选择一张图片:
在这里插入图片描述

这个浏览文件是一个现成的窗体 JFileChooser 具体使用:

   @Test
    public void test03() {
        JFileChooser chooser = new JFileChooser();
        chooser.setDialogTitle("文件资源选择");
//      设置默认选择路径     new File(".")//当前文件的目录,,
        chooser.setCurrentDirectory(new File("D://"));
//      设置可选择文件
//      FILES_ONLY: 只能选文件;DIRECTORIES_ONLY: 只能选文件夹;
//      FILES_AND_DIRECTORIES: 文件和文件夹都可以选。
        chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
        chooser.setMultiSelectionEnabled(true);//是否可多选,默认false
//        设置文件过滤器(可选择的文件类型):默认所有文件
//        chooser.setFileFilter("提示信息","后缀1","2");//设置默认使用的文件过滤器
//        chooser.addChoosableFileFilter(..);//设置候选的文件过滤器
//     eg:
        chooser.addChoosableFileFilter(
                new FileNameExtensionFilter("zip(*.rar,...)", "zip", "rar", "7z"));//压缩文件过滤器
        chooser.setApproveButtonText("这是选择按钮");// 设置按钮文本
//        CANCEL_OPTION: 点击了取消或关闭 ;APPROVE_OPTION: 点击了确认或保存 ;
//        ERROR_OPTION: 出现错误。
        int state=chooser.showOpenDialog(null);
        if(state== JFileChooser.APPROVE_OPTION){
            // 点击了 这是选择按钮 
            // 获取选择的文件流,前面若是设置了多选这里记得用getSelectedFile接取
            File file = chooser.getSelectedFile();
            System.out.println(file.getAbsoluteFile().toString());
        }
    }

这里简单使用一下:

    /** 筛选图片*/
    private void scanPath() {
        JFileChooser chooser = new JFileChooser();
        chooser.setDialogTitle("筛选图片");
        chooser.setCurrentDirectory(new File("D://"));
        chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
        chooser.setMultiSelectionEnabled(false);
        // 设置默认筛选图片
        chooser.setFileFilter(
                new FileNameExtensionFilter("image(*.jpg,*.png,.gif)", "jpeg", "jpg", "png", "gif"));
        chooser.setApproveButtonText("选择");
        int state = chooser.showOpenDialog(null);
        if (state == JFileChooser.APPROVE_OPTION) {
            //     获取选择的文件流
            File pathFiles = chooser.getSelectedFile();
            if (!pathFiles.isDirectory()) {
                // 当选择的是文件的时候触发记录绝对路径,
                // 没考虑闲的无聊改筛选设置为全部,然后选不是图片的文件。
                inputPath = pathFiles.getAbsolutePath();
                。。。
            }
        }
    }

这个文件选择的弹框是现成的,也可以自己写一些功能弹框。

注意事项:
// 子窗体的关闭的配置  不要使用 EXIT_ON_CLOSE
child.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
// 子窗体关闭除了点×还可以在按钮事件里调用 System.exit(0); 关闭

这是选择图片后的预览:
在这里插入图片描述

因为是直接在面板绘制的没考虑画面重叠的问题这里简单解决一些:

// 获取面板画笔对象
final Graphics g = imageBox.getGraphics();
// 这里设置画笔颜色为面板颜色,然后调用填充方法直接把整个面板初始化为背景色
g.setColor(imageBox.getBackground());
g.fillRect(0,0,imageBox.getWidth(),imageBox.getHeight());

BufferedImage img2 = null;
try {
    img2 = Thumbnails.of(image).size(imageBox.getWidth(),imageBox.getHeight())
        .asBufferedImage();
} catch (IOException e) {
    e.printStackTrace();
}
assert img2 != null;
g.drawImage(img2, 0, 0, null);

双缓冲

这样虽然可以解决,但是会绘制两次,有点闪,所有可以先用画笔在图片上绘制,处理好之后在统一绘制到面板上,这样也可以避免一些高帧渲染问题。

// 获取面板画笔对象
final Graphics g = imageBox.getGraphics();
//            // 这里设置画笔颜色为面板颜色,然后调用填充方法直接把整个面板初始化为背景色
//            g.setColor(imageBox.getBackground());
//            g.fillRect(0,0,imageBox.getWidth(),imageBox.getHeight());
BufferedImage img2 = null;
try {
    img2 = Thumbnails.of(image).size(imageBox.getWidth(), imageBox.getHeight()).asBufferedImage();
} catch (IOException e) {
    e.printStackTrace();
}
assert img2 != null;
//            g.drawImage(img2, 0, 0, null);
// 新建图层,获取画笔对象,
BufferedImage img3 = new BufferedImage(imageBox.getWidth(), imageBox.getHeight(),BufferedImage.TYPE_INT_RGB);
Graphics g2d=img3.createGraphics();
g2d.setColor(imageBox.getBackground());
// img3图片底色填充,画笔也可以写文字
g2d.fillRect(0,0,img3.getWidth(),img3.getHeight());
g2d.drawImage(img2, 0, 0, null);
g.drawImage(img3, 0, 0, null);

这样处理后只用绘制一次,而且图片已经在缓存里绘制起来更快。

透明度

// 图层也可以是透明色
BufferedImage buffImg = new BufferedImage(width, heigth, BufferedImage.TYPE_INT_RGB);
/**获取画笔对象*/
Graphics2D g2d = buffImg.createGraphics();
// ----------  增加下面的代码使得背景透明  -----------------
buffImg = g2d.getDeviceConfiguration().createCompatibleImage(width, heigth, Transparency.TRANSLUCENT);
// 注,此时图片画笔对象需要重新获取一下
//        g2d.dispose();//释放画笔,可省
g2d = buffImg.createGraphics();

// 透明图层能用来干嘛我也不清楚,不过输出带透明度的图片格式记得设定png,因为jpg省空间但有损。
//文字水印,及简单图像
g2d.setColor(color);
// 设置 Font
g2d.setFont(new Font("微软雅黑", Font.ROMAN_BASELINE, 33));//默认:Dialog
//设置透明度:1.0f为透明度 ,值从0-1.0,依次变得不透明
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
g2d.drawString("水印", x, y);// 文字
g2d.drawRect(x,y,width,heigth);// 绘制矩形
g2d.fillPolygon(int[] x坐标,int[] y坐标,int 点数量);// 点连线闭合图形

这里的缩放也是使用 Thumbnails 的工具类方法,肯定还有其他同类型的工具类,如果只是应用程序进行鼠标滚轮缩放图片仅显示的话,缩放画布就可以了。

// 缩放画布
g.scale(scale, scale);
//  这个缩放的画笔对象是面板,原图直接绘制,
double scale = 面板宽*1.0/原图宽;
// 如果用 双缓冲 那新建图层的长宽就是,面板长,宽/scale
// 这种缩放简单,只能用于显示,没有处理后的结果不能保存;

这里的缩放也是使用 Thumbnails 的工具类方法,肯定还有其他同类型的工具类,如果只是应用程序进行鼠标滚轮缩放图片仅显示的话,缩放画布就可以了。

// 缩放画布
g.scale(scale, scale);
//  这个缩放的画笔对象是面板,原图直接绘制,
double scale = 面板宽*1.0/原图宽;
// 如果用 双缓冲 那新建图层的长宽就是,面板长,宽/scale
// 这种缩放简单,只能用于显示,没有处理后的结果不能保存;

下载地址

已经打好exe包:https://pan.baidu.com/s/1cen_C6zZrauoJhWyYNuV1A?pwd=6666
源码:https://pan.baidu.com/s/17Xop5sXA2Bgf0xploa68vg?pwd=6666

jar包运行需要 jre 运行环境, 通过exe4j 可以一起打成 exe包直接运行。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java 中,可以使用 `ImageIO` 类和 `BufferedImage` 类来完成将图片转换成 `.ico` 文件的操作。具体步骤如下: 1. 读取图片文件: ```java BufferedImage image = ImageIO.read(new File("input.png")); ``` 2. 创建 `ImageOutputStream` 对象: ```java ImageOutputStream outputStream = ImageIO.createImageOutputStream(new File("output.ico")); ``` 3. 创建 `ImageWriter` 对象: ```java Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("ico"); ImageWriter writer = writers.next(); ``` 4. 创建 `ImageWriteParam` 对象: ```java ImageWriteParam writeParam = writer.getDefaultWriteParam(); ImageTypeSpecifier typeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB); IIOMetadata metadata = writer.getDefaultImageMetadata(typeSpecifier, writeParam); ``` 5. 设置 `IIOMetadata`: ```java Element tree = (Element) metadata.getAsTree("javax_imageio_1.0"); Element node = tree.getElementsByTagName("ImageDescriptor").item(0); node.setAttribute("bitsPerPixel", "32"); node.setAttribute("compression", "BI_RGB"); metadata.setFromTree("javax_imageio_1.0", tree); ``` 6. 写入图片: ```java writer.setOutput(outputStream); writer.write(metadata, new IIOImage(image, null, metadata), writeParam); ``` 7. 关闭资源: ```java writer.dispose(); outputStream.close(); ``` 完整代码示例: ```java import javax.imageio.*; import javax.imageio.metadata.*; import javax.imageio.plugins.bmp.*; import javax.imageio.stream.*; import java.awt.image.*; import java.io.*; import java.util.*; public class ImageToICO { public static void main(String[] args) throws Exception { // 读取图片文件 BufferedImage image = ImageIO.read(new File("input.png")); // 创建 ImageOutputStream 对象 ImageOutputStream outputStream = ImageIO.createImageOutputStream(new File("output.ico")); // 创建 ImageWriter 对象 Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("ico"); ImageWriter writer = writers.next(); // 创建 ImageWriteParam 对象 ImageWriteParam writeParam = writer.getDefaultWriteParam(); ImageTypeSpecifier typeSpecifier = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB); IIOMetadata metadata = writer.getDefaultImageMetadata(typeSpecifier, writeParam); // 设置 IIOMetadata Element tree = (Element) metadata.getAsTree("javax_imageio_1.0"); Element node = tree.getElementsByTagName("ImageDescriptor").item(0); node.setAttribute("bitsPerPixel", "32"); node.setAttribute("compression", "BI_RGB"); metadata.setFromTree("javax_imageio_1.0", tree); // 写入图片 writer.setOutput(outputStream); writer.write(metadata, new IIOImage(image, null, metadata), writeParam); // 关闭资源 writer.dispose(); outputStream.close(); } } ``` 注意:以上代码是将 png 格式图片转换ico 格式图片,如果需要将其他格式图片转换ico 格式,请将代码中的 `ImageIO.read(new File("input.png"))` 和 `new File("output.ico")` 分别替换成对应的图片文件路径。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值