解决ImageIO无法读取部分JPEG格式图片问题
解决ImageIO无法读取部分JPEG格式图片问题
问题描述
我最近对在线聊天功能进行了一些内存优化,结果在回归测试时,突然发现有张图片总是发送失败。测试同事把问题转到我这儿来看,我仔细检查了一下,发现是上传文件的接口报错,说文件格式不符合要求。乍一看这问题似乎很简单,文件格式限制而已。我心想:JPEG 格式不应该是允许的么?然而,当我右键查看文件属性,心里瞬间有种不好的预感——这张图片确实是 JPEG 格式的,而系统明明允许上传 JPEG 类型的文件。这就变得有趣了。
问题排查
首先,我查看了测试环境的日志,却没有任何有用的线索。然后打开上传服务的代码,检查文件处理的逻辑,看起来一切正常,没有明显问题。既然看不出来问题,那就只能踏踏实实地 debug 了。
服务启动后,我用另一张 JPEG 图片测试了一下,结果上传成功了。这让我怀疑测试环境的代码和我们本地的版本有差异。于是,我再次使用之前总是上传失败的图片,测试后同样报了和测试环境一样的错误。我将断点打在文件校验的部分,逐行调试,结果发现所有的校验步骤都通过了!看来问题不在文件类型校验上。继续深入调试,发现流程走到了文件为空的逻辑,然后直接返回了“不允许上传该文件类型”的错误。这让我摸不着头脑——文件明明有大小,而且后端也没有报错,怎么会读取不到文件内容?
接着,我看了一下获取图片内容的代码:
BufferedImage image = ImageIO.read(fileData.getInputStream());
看起来平平无奇,但是这个image
对象返回来的确实是null
。
问题原因
经过深入分析,终于找到了问题的根源:ImageIO.read()
方法在 Java 中并不支持 .webp
格式图片的读取。这是因为 ImageIO
类依赖的 SPI(Service Provider Interface)
机制,只为常见的图片格式(如 PNG
、JPEG
、GIF
等)注册了相应的读取器,但并没有对较新的 WEBP 格式提供内置支持。
当我们尝试用记事本打开那张图片时,发现它的确是 WEBP
格式,而不是我们最初以为的 JPEG
。这就解释了为什么系统上传失败——ImageIO.read()
方法无法处理 WEBP
格式的文件,导致图片无法被正确读取,进而触发了文件格式不符合要求的错误。
有问题的JEPG
图片数据:
正常的JEPG
图片数据:
问题修复
解决这个问题也非常简单,直接在pom文件引入如下组件:
<dependency><groupId>org.sejda.imageio</groupId><artifactId>webp-imageio</artifactId><version>0.1.6</version></dependency>
然后就可以了!!!
相关文章:

解决ImageIO无法读取部分JPEG格式图片问题
解决ImageIO无法读取部分JPEG格式图片问题 问题描述 我最近对在线聊天功能进行了一些内存优化,结果在回归测试时,突然发现有张图片总是发送失败。测试同事把问题转到我这儿来看,我仔细检查了一下,发现是上传文件的接口报错&#…...

使用three.js 实现蜡烛效果
使用three.js 实现蜡烛效果 import * as THREE from "three" import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js"var scene new THREE.Scene(); var camera new THREE.PerspectiveCamera(60, window.innerWidth / window.in…...

手动在Linux服务器上部署并运行SpringBoot项目(新手向)
背景 当我们在本地开发完应用并且测试通过后,接着就要部署在服务器上启动。 步骤 1.先用maven将SpringBoot应用当成jar包 2.生成jar文件并复制此文件 3.xshell远程连接linux服务器,在xftp将文件粘贴到linux服务器,这里我放在/usr/local…...
自媒体短视频如何制作?
从0到1打造爆款短视频!300条视频创作经验分享,助你玩转自媒体! 想用短视频玩转自媒体却不知道从何下手?别担心!从21年开始接触短视频的我,断断续续创作了300多条视频,踩过不少坑,也收获了一些心得,核心秘诀就是:账号内容垂直化 + 明确受众群体! 我将从主题确定、脚本…...

2024年河南省职业技能竞赛(网络建设与运维赛项)
模块二:网络建设与调试 说明: 1.所网络设备在创建之后都可以直接通过 SecureCRT 软件 telnet 远程连接操作。 2.要求在全员化竞赛平台中保留竞赛生成的所有虚拟主机。 3.题目中所有所有的密码均为 Pass-1234,若未按照要求设置,涉 …...

git--git reset
HEAD 单独一个HEAD eg:git diff HEAD 表示当前结点。 HEAD~ HEAD~只处理当前分支。 注意:master分支的上一个结点是tmp分支的所在的结点fc11b74, 79f109e才是master的第二个父节点。 HEAD~ 当前结点的父节点。 HEAD~1 当前结点的父节点。 HEAD~n 当前结点索…...
Spring Boot的实用内置功能详解
Spring Boot作为一款备受欢迎的Java框架,以其简洁、高效和易用的特点,赢得了广大开发者的青睐。其内置的多种功能更是为开发者提供了极大的便利,本文将详细介绍Spring Boot中记录请求数据、请求/响应包装器、特殊的过滤器Filter以及Controlle…...

撸猫变梳毛?怎么解决猫咪掉毛问题?好用的宠物空气净化器推荐
秋风一吹,新一轮的猫咪换毛季又到了,这也意味着我失去了撸猫自由。我每天的治愈方式就是下班撸猫,抚摸着柔软的毛发,好像一天的烦恼都消除了。可是一到换毛季,猫还没撸两下,先从猫咪身上带下一手毛…...

人声分离免费软件,六款好用软件处理音乐更轻松!
在这个数字化音乐时代,无论是专业音乐人还是音乐爱好者,都渴望在创作与编辑过程中拥有更多便捷高效的工具。人声分离技术,作为音乐后期制作中的一项关键技术,能够精准地将歌曲中的人声与伴奏分离,极大地拓宽了音乐创作…...

数据分析Power BI设置万为单位的数据
玩过Power BI的同学都知道,power BI在度量值设置单位里,唯独没有万这个单位,但是我们可以自定义,操作过程如下: 1.用DAX新建单位表 单位 SELECTCOLUMNS( { ( "元", 1), ("万",10000), ("千…...

(AI 生成) 新时代游击方式: 利用 “灵活就业“ 红利
注意: 本文内容为 AI 大模型生成, 仅供参考. 提示词: 写一篇短文, 500 字左右, 标题为: 新时代游击方式: 利用 “灵活就业” 红利 1 豆包 《新时代游击方式:利用“灵活就业”红利》 在新时代的大舞台上,“灵活就业”犹如一块熠熠生辉的宝藏,…...

Unity UndoRedo(撤销重做)功能
需求 撤销与重做功能 思考 关于记录的数据的两点思考: 记录操作记录影响显示和逻辑的所有数据 很显然这里就要考虑取舍了: 记录操作 这种方案只需要记录每一步的操作,具体这个操作要怎么渲染和实现出来完全需要自己去实现,这…...

28条有关人工智能的名言
当谈到人工智能(AI)的潜力和潜在风险,以及无人类干预的机器学习和推理过程时,目前尚存在许多不同的观点。 只有时间会告诉我们,这些语录中哪一条是最接近未来的真实情况的。在我们尚未到达目的地之前,想一想…...
搞机器视觉项目看不起搞机器视觉培训的,实际上怎么样
搞机器视觉项目第一要务就是验收回款,往往欠款的非常严重,多数还要打通人际关系需要大量的成本。大多数机器视觉检测项目具有一定的风险,客户要求不明确,技术评估不充分,往往伴随着失败的可能性。所以做项目又累又担风…...

使用Jenkins部署项目
部署中的痛点 为什么要用Jenkins?我说下我以前开发的痛点,在一些中小型企业,每次开发一个项目完成后,需要打包部署,可能没有专门的运维人员,只能开发人员去把项目打成一个exe包,可能这个项目已…...
【机器学习与神经网络荣获诺贝尔奖】科学边界的扩展及技术革新
【机器学习与神经网络荣获诺贝尔奖】科学边界的扩展及技术革新 1)科学交叉融合的体现2)方法论的创新3)社会影响的考量 一、机器学习与神经网络的发展前景1)生产制造领域2)金融领域3)医疗领域 二、机器学习和…...
Javascript扩展符号(...)使用说明
在 ES6 中,扩展运算符(spread operator)... 可以用于在函数调用、数组字面量或对象字面量中展开数组或对象。以下是扩展运算符的一些常见用法: 1. 在函数调用中使用扩展运算符 扩展运算符可以在函数调用时展开数组或对象&#x…...

giugughk
c语言中的小小白-CSDN博客c语言中的小小白关注算法,c,c语言,贪心算法,链表,mysql,动态规划,后端,线性回归,数据结构,排序算法领域.https://blog.csdn.net/bhbcdxb123?spm1001.2014.3001.5343 给大家分享一句我很喜欢我话: 知不足而奋进,望远山而前行&am…...

【微服务】网关 - Gateway(下)(day8)
网关过滤工厂 在上一篇文章中,主要是对网关进行了一个总体的介绍,然后对网关中的断言进行了一个描述。在这篇文章中,主要是对网关中的最后一大核心——过滤进行介绍。 当客户端发送过来的请求经过断言之后,如果还想在请求前后添…...

【C#】创建一个控制台应用程序来管理学生成绩
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 在C#中创建一个控制台应用程序来管理学生成绩编写程序程序解释 在C#中创建一个控制台应用程序来管理学生成绩 在这篇文章中,我将向你展示如何使用C#创建…...

第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...

边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...