Java中BufferedImage加载竖版图片宽高被交换问题求助
竖版图片读取后宽高被交换的原因及解决方案
你遇到的问题核心是竖版图片的EXIF方向元数据未被处理:
很多手机或相机拍摄竖图时,会将图片以横版像素格式存储,同时在EXIF元数据中写入Orientation(方向)标签(比如顺时针旋转90度),用于告诉显示设备正确的展示方向。但ImageIO.read()方法只会读取图片的原始像素宽高,不会自动根据EXIF的方向信息调整视觉上的宽高,导致你获取到的是像素层面的原始尺寸,而非实际显示的宽高。
解决思路
读取图片的EXIF方向标签,根据标签值修正宽高,或者直接将图片旋转到正确方向后再获取宽高。
方法1:使用第三方库简化处理(推荐)
原生JDK处理EXIF元数据非常繁琐,推荐使用Apache Commons Imaging(原Sanselan)库,它能轻松读取EXIF信息并自动修正图片方向。
- 引入Maven依赖:
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-imaging</artifactId> <version>1.0-alpha3</version> </dependency>
- 代码示例:
import org.apache.commons.imaging.ImageInfo; import org.apache.commons.imaging.Imaging; import java.io.File; public class ImageOrientationFix { public static void main(String[] args) throws Exception { File imgFile = new File("your-image-path.jpg"); // 读取包含EXIF方向的图片信息 ImageInfo imageInfo = Imaging.getImageInfo(imgFile); int orientation = imageInfo.getOrientation(); // 根据方向标签修正宽高 int pixelWidth = imageInfo.getWidth(); int pixelHeight = imageInfo.getHeight(); int actualWidth, actualHeight; // 方向标签对应的宽高转换规则 switch (orientation) { // 顺时针/逆时针90度相关方向,宽高互换 case 5: case 6: case 7: case 8: actualWidth = pixelHeight; actualHeight = pixelWidth; break; // 其他方向宽高不变 default: actualWidth = pixelWidth; actualHeight = pixelHeight; break; } System.out.println("视觉实际宽:" + actualWidth + ",视觉实际高:" + actualHeight); // 若需要直接获取修正方向后的图片,可使用以下代码 // BufferedImage correctedImage = Imaging.getBufferedImage(imgFile); // int correctedWidth = correctedImage.getWidth(); // int correctedHeight = correctedImage.getHeight(); } }
方法2:原生JDK读取EXIF方向(不推荐,繁琐)
如果不想引入第三方库,可通过JDK的IIOMetadata解析EXIF的Orientation标签,但仅支持JPEG等部分格式,代码复杂度高:
import javax.imageio.ImageIO; import javax.imageio.ImageReader; import javax.imageio.metadata.IIOMetadata; import javax.imageio.metadata.IIOMetadataNode; import javax.imageio.stream.ImageInputStream; import java.io.File; import java.util.Iterator; public class NativeExifOrientationReader { public static int getOrientation(File imageFile) throws Exception { try (ImageInputStream stream = ImageIO.createImageInputStream(imageFile)) { Iterator<ImageReader> readers = ImageIO.getImageReaders(stream); if (!readers.hasNext()) { return 1; // 默认正常方向 } ImageReader reader = readers.next(); try { reader.setInput(stream); IIOMetadata metadata = reader.getImageMetadata(0); String exifFormat = "javax_imageio_jpeg_image_1.0"; if (metadata.containsMetadata(exifFormat)) { IIOMetadataNode root = (IIOMetadataNode) metadata.getAsTree(exifFormat); IIOMetadataNode exifNode = (IIOMetadataNode) root.getElementsByTagName("exif").item(0); if (exifNode != null) { IIOMetadataNode ifdNode = (IIOMetadataNode) exifNode.getElementsByTagName("ExifIFD").item(0); if (ifdNode != null) { for (int i = 0; i < ifdNode.getLength(); i++) { IIOMetadataNode entryNode = (IIOMetadataNode) ifdNode.item(i); if ("Orientation".equals(entryNode.getAttribute("tagname"))) { return Integer.parseInt(entryNode.getAttribute("value")); } } } } } } finally { reader.dispose(); } return 1; } } public static void main(String[] args) throws Exception { File imgFile = new File("your-image-path.jpg"); int orientation = getOrientation(imgFile); BufferedImage srcImage = ImageIO.read(imgFile); int pixelWidth = srcImage.getWidth(); int pixelHeight = srcImage.getHeight(); int actualWidth, actualHeight; switch (orientation) { case 5: case 6: case 7: case 8: actualWidth = pixelHeight; actualHeight = pixelWidth; break; default: actualWidth = pixelWidth; actualHeight = pixelHeight; break; } System.out.println("视觉实际宽:" + actualWidth + ",视觉实际高:" + actualHeight); } }
内容的提问来源于stack exchange,提问作者user20519169
相关产品推荐
相关产品推荐

