优化图片文件过大导致网页加载慢问题中对于压缩png动图失败案例总结

作者:丘杨(如需转载请注明出处)

持续更新ing............

背景:

网页中图片和视频资源较多且文件较大,导致网页加载非常慢。图片和视频均存储于minio中,前端会直接访问minio链接

故尝试后端通过压缩图片,前端只展示压缩后的图片来优化加载速度过慢的问题。

其中遇到的一大难题是png动图经过压缩后失去了动图效果。

可能原因:

以下是gpt针对于这个问题可能原因的回答

PNG动图压缩后失去动画效果可能是由于以下原因:

  1. 压缩算法或参数设置不正确:压缩PNG动图时,如果使用不适当的压缩算法或参数设置,可能会导致图像数据损坏或帧序混乱,从而失去动画效果。
  2. 压缩软件存在问题:使用的压缩软件可能存在bug或问题,导致在压缩过程中出现错误或异常,从而无法保留动画效果。
  3. 压缩后文件格式不支持动画:如果压缩后的文件格式不支持动画,例如某些PNG图片查看器不支持GIF格式的动画,那么压缩后的动图可能会失去动画效果。
  4. 软件缓存问题:某些软件缓存可能会导致动画效果无法正确显示,特别是在多次压缩或转换之后,缓存可能会干扰图像的显示和播放。

为了确保PNG动图压缩后保留动画效果,可以采取以下措施:

  1. 使用适当的压缩算法和参数:在压缩PNG动图时,选择适当的压缩算法和参数,例如使用优速文件件压缩器等软件工具进行压缩时,可以选择不改变图片分辨率的压缩方式,以确保动画效果得到保留。
  2. 使用可靠的压缩软件:选择经过测试和验证的可靠压缩软件,确保软件在压缩过程中不会对图像造成损坏或出现异常。
  3. 检查输出文件格式:在压缩之前,检查输出文件的格式是否支持动画效果,例如GIF格式支持动画,而PNG格式则不支持。如果需要保留动画效果,应该选择支持动画的格式进行输出。
  4. 清除软件缓存:在使用软件进行压缩之后,可以尝试清除软件缓存,以确保图像的显示和播放不会受到缓存的影响。

失败案例记载:

一、jpedal:PngCompressor.compress(inputStream, outputStream);

maven:

        <dependency>
            <groupId>org.jpedal</groupId>
            <artifactId>OpenViewerFX</artifactId>
            <version>6.6.14</version>
        </dependency>

代码:

import com.idrsolutions.image.png.PngCompressor;    

    public void addCompression(String fileName) {
        try {
            // 读取minio获取文件流并重新上传,更新url readService具体方法见文末
            InputStream inputStream = readService.getFileInputStream(bucketName, fileName);
            String compressName = "compress_" + fileName;
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            PngCompressor.compress(inputStream, outputStream);
            byte[] byteArray = outputStream.toByteArray();
            try {                // writeService具体方法见文末
                writeService.upload(byteArray, compressName);
                try {
                    outputStream.close();
                } catch (Exception ignored) {
                }
                try {
                    inputStream.close();
                } catch (Exception ignored) {
                }
            } catch (Exception e) {
                e.printStackTrace();
                throw e;
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw e;        
            }
    }

结果:

从1.6mb的文件压缩到9.6kb,但是失去了动画效果

参考文献地址:

Java压缩png图片文件大小,效果跟Tinypng压缩效果大致一样_openviewerfx7.0使用-CSDN博客

二、对图片进行原比例无损压缩,压缩后覆盖原图片

方式1:BufferedImage+Graphics2D

代码:
import java.awt.image.BufferedImage;

     public void addCompression(String fileName) {
        try {
            // 读取minio获取文件流并重新上传,更新url readService具体方法见文末
            InputStream inputStream = readService.getFileInputStream(bucketName, fileName);
            String compressName = "compress_" + fileName;
            // 读取原始动图文件
            BufferedImage img = ImageIO.read(inputStream);

            int newWidth = img.getWidth();
            int newHeight = img.getHeight();

            // 创建目标尺寸的缓冲图像
            BufferedImage tag = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);

            // 获取绘图对象并在目标图像上绘制原始图像
            Graphics2D graphics = img.createGraphics();
            graphics.drawImage(img, 0, 0, newWidth, newHeight, null);
            graphics.dispose();
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            ImageIO.write(tag, "png", outputStream);
            writeService.upload(outputStream.toByteArray(),  compressName);
        } catch (IOException e) {
            e.printStackTrace();
            throw e;        
            }
    }
结果:

压缩后的图像只剩下120b,且打开为

导致这个问题的原因暂未找到

参考文献地址:

java动图压缩_mob649e815cb099的技术博客_51CTO博客

图片压缩算法(宽高不变)-CSDN博客

方式2:BufferedImage

代码:
import java.awt.image.BufferedImage;

     public void addCompression(String fileName) {
        try {
            // 读取minio获取文件流并重新上传,更新url readService具体方法见文末
            InputStream inputStream = readService.getFileInputStream(bucketName, fileName);
            String compressName = "compress_" + fileName;
            // 读取原始动图文件
            BufferedImage img = ImageIO.read(inputStream);

            int newWidth = img.getWidth();
            int newHeight = img.getHeight();

            // 创建目标尺寸的缓冲图像
            BufferedImage tag = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
            tag.getGraphics().drawImage(image.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH), 0, 0, null);
            ImageIO.write(tag, "png", outputStream);
            writeService.upload(outputStream.toByteArray(),  compressName);
        } catch (IOException e) {
            e.printStackTrace();
            throw e;        
            }
    }
结果:

从1.6mb压缩到19.9kb,图片可正常显示但无动画效果

参考文献地址:

java无损压缩图片_想养一只!的博客-CSDN博客

三、ImageWriter压缩后生成字节流

方式1:

代码:

     public void addCompression(String fileName) {
        try {
            // 读取minio获取文件流并重新上传,更新url readService具体方法见文末
            InputStream inputStream = readService.getFileInputStream(bucketName, fileName);
            String compressName = "compress_" + fileName;
            // 读取原始动图文件
            BufferedImage image = ImageIO.read(inputStream);
            // 得到指定Format图片的writer(迭代器)
            Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName("png");
            // 得到writer
            ImageWriter writer = (ImageWriter) iter.next();
            // 得到指定writer的输出参数设置(ImageWriteParam )
            ImageWriteParam iwp = writer.getDefaultWriteParam();
            // 设置可否压缩
            iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            // 设置压缩质量参数
            float quality = 0.5f;
            iwp.setCompressionQuality(quality);
            iwp.setProgressiveMode(ImageWriteParam.MODE_DISABLED);
            ColorModel colorModel = ColorModel.getRGBdefault();
            // 指定压缩时使用的色彩模式
            iwp.setDestinationType(
                    new javax.imageio.ImageTypeSpecifier(colorModel, colorModel.createCompatibleSampleModel(16, 16)));
            // 开始打包图片,写入byte[]
            // 取得内存输出流
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            IIOImage iIamge = new IIOImage(image, null, null);
            // 此处因为ImageWriter中用来接收write信息的output要求必须是ImageOutput
            // 通过ImageIo中的静态方法,得到byteArrayOutputStream的ImageOutput
            writer.setOutput(ImageIO.createImageOutputStream(byteArrayOutputStream));
            writer.write(null, iIamge, iwp);
            byte[] imgBytes = byteArrayOutputStream.toByteArray();
            writeService.upload(imgBytes, compressName);        
        } catch (IOException e) {
            e.printStackTrace();
            throw e;        
            }
    }

结果:

png图像从1.6mb压缩至27.7kb,但失去动图效果

参考文献地址:

java无损压缩图片_想养一只!的博客-CSDN博客

方式2:

由于方式1失去动图效果,基于gpt给的方法进行优化,其中增加了IIOMetadata

代码:

     public void addCompression(String fileName) {
        try {
            // 读取minio获取文件流并重新上传,更新url readService具体方法见文末
            InputStream inputStream = readService.getFileInputStream(bucketName, fileName);
            String compressName = "compress_" + fileName;
            // 读取原始动图文件
            BufferedImage image = ImageIO.read(inputStream);
            // 得到指定Format图片的writer(迭代器)
            Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName("png");
            // 得到writer
            ImageWriter writer = (ImageWriter) iter.next();
            // 得到指定writer的输出参数设置(ImageWriteParam )
            ImageWriteParam iwp = writer.getDefaultWriteParam();
            // 设置可否压缩
            iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            // 设置压缩质量参数
            float quality = 0.5f;
            iwp.setCompressionQuality(quality);
            iwp.setProgressiveMode(ImageWriteParam.MODE_DISABLED);
            ColorModel colorModel = ColorModel.getRGBdefault();
            // 指定压缩时使用的色彩模式
            iwp.setDestinationType(
                    new javax.imageio.ImageTypeSpecifier(colorModel, colorModel.createCompatibleSampleModel(16, 16)));
            // 开始打包图片,写入byte[]
            // 取得内存输出流
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            IIOImage iIamge = new IIOImage(image, null, null);
            // 此处因为ImageWriter中用来接收write信息的output要求必须是ImageOutput
            // 通过ImageIo中的静态方法,得到byteArrayOutputStream的ImageOutput
            writer.setOutput(ImageIO.createImageOutputStream(byteArrayOutputStream));
            writer.write(null, iIamge, iwp);
            byte[] imgBytes = byteArrayOutputStream.toByteArray();
            writeService.upload(imgBytes, compressName);        
        } catch (IOException e) {
            e.printStackTrace();
            throw e;        
            }
    }

结果:

文件从1.6mb压缩到56.5kb,png依旧失去动画效果

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
如果前端项目图片加载,即使图片的体积并不大,可以考虑以下几种优化方式: 1. 图片压缩:使用工具来压缩图片的大小,以减少文件大小,例如使用在线工具或者构建工具(如Webpack)图片压缩插件。 2. 图片格式选择:根据图片的内容和用途选择合适的图片格式。JPEG 格式适用于照片和带有丰富颜色的图片,而 PNG 格式适用于图标和简单颜色的图像。WebP 是一种现代的图片格式,可提供更好的压缩效率和更小的文件大小,但需要注意浏览器兼容性。 3. 图片加载:延迟加载非首屏可见区域的图片,只有当用户滚动到相关区域时再进行加载。这样可以减少初始加载时的资源消耗。可以使用一些插件或库来实现图片加载,如Intersection Observer API。 4. CDN 加速:将图片等静态资源存储在内容分发网络(CDN)上,将资源分发到全球各地的服务器节点。这样可以提高图片加载速度,减少网络延迟。 5. 图片加载:提前加载页面需要使用的重要图片资源,以便在需要时能够立即展示。可以通过 JavaScript 预加载技术或者使用 `<link rel="preload">` 标签来实现。 6. 响应式图片:为不同屏幕尺寸提供适应的图片资源,避免加载过大图片。可以使用 `<picture>` 元素、CSS 媒体查询或者响应式图片库来实现。 通过综合运用这些优化策略,可以有效减少图片加载时间,提升前端项目的性能和用户体验。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

樱曦何归

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值