public static String getImageFormatName_v1( File imageFile ) {
        try (ImageInputStream imageInputStream = ImageIO.createImageInputStream(imageFile)) {
            Iterator<ImageReader> imageReadersList = ImageIO.getImageReaders(imageInputStream);
            if (!imageReadersList.hasNext()) {
                log.error("Cannot detect image format by ImageIO.getImageReaders" );
                return ImageUtils.getImageFormatByHeader( imageFile );
            }
            return imageReadersList.next().getFormatName();
        } catch (IOException e) {
            log.error( CommonConstans.EXCEPTION_LOG_PREFIX,e );
            throw new BusinessLogicException( "失败" );
        }
    }
 public static String getImageFormatByHeader(File imageFile) {
        // 读取文件前12字节(覆盖所有格式的头部长度)
        byte[] header = new byte[12];
        try (FileInputStream fis = new FileInputStream(imageFile)) {
            int bytesRead = fis.read(header);
            if (bytesRead < 12) {  // 处理小文件场景
                header = Arrays.copyOf(header, bytesRead);
            }
        } catch (Exception e) {
            log.error(CommonConstans.EXCEPTION_LOG_PREFIX, e);
            return null;
        }

        // 按格式特征优先级检测(特征越独特越靠前)
        if (isWebP(header)) {
            return "WEBP";
        } else if (isPNG(header)) {
            return "PNG";
        } else if (isGIF(header)) {
            return "GIF";
        } else if (isTIFF(header)) {
            return "TIFF";
        } else if (isBMP(header)) {
            return "BMP";
        } else if (isJPEG(header)) {
            return "JPEG";
        }
        return null;
    }
 //--- 各格式检测逻辑 ---//
    private static boolean isJPEG(byte[] header) {
        return header.length >= 2
                && (header[0] & 0xFF) == 0xFF
                && (header[1] & 0xFF) == 0xD8;
    }

    private static boolean isPNG(byte[] header) {
        return header.length >= 8
                && header[0] == (byte) 0x89
                && header[1] == 0x50   // P
                && header[2] == 0x4E   // N
                && header[3] == 0x47   // G
                && header[4] == 0x0D
                && header[5] == 0x0A
                && header[6] == 0x1A
                && header[7] == 0x0A;
    }

    private static boolean isGIF(byte[] header) {
        if (header.length < 6) return false;
        String headerStr = new String(header, 0, 6, StandardCharsets.US_ASCII);
        return "GIF87a".equals(headerStr) || "GIF89a".equals(headerStr);
    }

    private static boolean isBMP(byte[] header) {
        return header.length >= 2
                && header[0] == 0x42   // B
                && header[1] == 0x4D;  // M
    }

    private static boolean isWebP(byte[] header) {
        return header.length >= 12
                && header[0] == 0x52   // R
                && header[1] == 0x49   // I
                && header[2] == 0x46   // F
                && header[3] == 0x46   // F
                && header[8] == 0x57   // W
                && header[9] == 0x45   // E
                && header[10] == 0x42  // B
                && header[11] == 0x50; // P
    }

    private static boolean isTIFF(byte[] header) {
        return header.length >= 4
                && ((header[0] == 0x49 && header[1] == 0x49 && header[2] == 0x2A && header[3] == 0x00)  // II*格式
                || (header[0] == 0x4D && header[1] == 0x4D && header[2] == 0x00 && header[3] == 0x2A)); // MM*格式
    }
  public static String getImageFormatName_v2( String imageUrl ) {
        ImageInputStream iis = null;
        try{
            URL url = new URL(imageUrl);
            iis = ImageIO.createImageInputStream( url.openStream() );
            Iterator<ImageReader> imageReadersList = ImageIO.getImageReaders(iis);
            if (!imageReadersList.hasNext()) {
                log.error("Cannot detect image format by ImageIO.getImageReaders" );
                return ImageUtils.getImageFormatByHeader( imageUrl );
            }
            return imageReadersList.next().getFormatName();
        } catch (IOException e) {
            log.error( CommonConstans.EXCEPTION_LOG_PREFIX,e );
            throw new BusinessLogicException( "失败" );
        }finally {
            MyFileUtils.closeCloseable( iis );
        }
    }

 public static String getImageFormatByHeader(String imageUrl) {
        // 1. 验证URL有效性
        if (imageUrl == null || imageUrl.isEmpty()) {
            log.error("Invalid image URL");
            return null;
        }

        // 2. 创建HTTP连接
        try (InputStream urlStream = new URL(imageUrl).openStream();
             BufferedInputStream bufferedStream = new BufferedInputStream(urlStream)) {

            // 3. 读取前12字节(文件头)
            byte[] header = new byte[12];
            int bytesRead = bufferedStream.read(header, 0, 12);
            if (bytesRead < 12) {
                header = Arrays.copyOf(header, bytesRead);
            }

            // 4. 格式检测逻辑(与原方法一致)
            if (isWebP(header)) {
                return "WEBP";
            } else if (isPNG(header)) {
                return "PNG";
            } else if (isGIF(header)) {
                return "GIF";
            } else if (isTIFF(header)) {
                return "TIFF";
            } else if (isBMP(header)) {
                return "BMP";
            } else if (isJPEG(header)) {
                return "JPEG";
            }
        } catch (MalformedURLException e) {
            log.error("Malformed URL: {}", imageUrl);
        } catch (IOException e) {
            log.error("Failed to read from URL: {}", imageUrl);
        }
        return null;
    }
  /**
     * 多次调用该方法获取 multipartFile 表示图片的图片格式不会影响后续对 multipartFile 的使用,
     * 因为 Spring 的 MultipartFile 实现(如 StandardMultipartFile)‌默认基于临时文件存储上传内容‌,这使得:
     * ‌每次调用 getInputStream() 会返回一个新的 InputStream‌,从头开始读取文件。
     * ‌流的独立性‌:每个 InputStream 实例独立读取文件,互不影响。
     * ‌每次 getInputStream()‌:生成新的文件输入流,读取前 12 字节后关闭流。
     * ‌不影响后续操作‌:所有读取操作均基于独立的流,文件指针始终从头开始。
     * @param imageFile
     * @return
     */
    public static String getImageFormatName_v3(MultipartFile imageFile) {
        try (InputStream fileStream = imageFile.getInputStream(); // 获取原始流
             ImageInputStream imageInputStream = ImageIO.createImageInputStream(fileStream)) { // 正确传递流
            if (imageInputStream == null) {
                log.error("无法创建ImageInputStream:输入流不可读");
                return null;
            }
            Iterator<ImageReader> readers = ImageIO.getImageReaders(imageInputStream);
            if (!readers.hasNext()) {
                log.error("Cannot detect image format by ImageIO.getImageReaders" );
                return ImageUtils.getImageFormatByHeader( imageFile );
            }
            // 获取格式名称(如 "JPEG", "PNG")
            return readers.next().getFormatName().toUpperCase();
        } catch (IOException e) {
            log.error("图片格式检测失败", e);
            return null;
        }
    }
 /**
     * 多次调用该方法获取 multipartFile 表示图片的图片格式不会影响后续对 multipartFile 的使用,
     * 因为 Spring 的 MultipartFile 实现(如 StandardMultipartFile)‌默认基于临时文件存储上传内容‌,这使得:
     * ‌每次调用 getInputStream() 会返回一个新的 InputStream‌,从头开始读取文件。
     * ‌流的独立性‌:每个 InputStream 实例独立读取文件,互不影响。
     * ‌每次 getInputStream()‌:生成新的文件输入流,读取前 12 字节后关闭流。
     * ‌不影响后续操作‌:所有读取操作均基于独立的流,文件指针始终从头开始。
     * @param multipartFile
     * @return
     */
    public static String getImageFormatByHeader(MultipartFile multipartFile) {
        // 验证文件有效性
        if (multipartFile == null || multipartFile.isEmpty()) {
            log.error("MultipartFile is null or empty");
            return null;
        }
        byte[] header = new byte[12];
        try (InputStream inputStream = multipartFile.getInputStream()) {
            // 1. 读取前12字节作为header
            int headerBytesRead = inputStream.read(header);
            if (headerBytesRead < 12) {
                header = Arrays.copyOf(header, headerBytesRead);
            }
        } catch (IOException e) {
            log.error(CommonConstans.EXCEPTION_LOG_PREFIX, e);
            return null;
        }

        // 格式检测逻辑
        if (isWebP(header)) {
            return "WEBP";
        } else if (isPNG(header)) {
            return "PNG";
        } else if (isGIF(header)) {
            return "GIF";
        } else if (isTIFF(header)) {
            return "TIFF";
        } else if (isBMP(header)) {
            return "BMP";
        } else if (isJPEG(header)) {
            return "JPEG";
        }
        return null;
    }
 public static String getImageFormatName_v4( String imageFilePath ) {
        return ImageUtils.getImageFormatName_v1( new File( imageFilePath ) );
    }
import cn.hutool.core.codec.Base64;
import com.drew.imaging.ImageMetadataReader;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifIFD0Directory;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Encoder;
import javax.imageio.*;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;
import javax.net.ssl.*;
import javax.xml.bind.DatatypeConverter;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.io.*;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐