互联网技术社区|福缘小草|程序员技术博客
🏠首页
  • 开发必备
  • Java
  • Spring Boot
  • MyBatis
  • C#
  • 架构
  • 算法
  • Vue
  • JavaScript
  • HTML
  • MySQL
  • Oracle
  • SQL Server
  • PostgreSQL
  • Redis
  • MongoDB
  • ElasticSearch
  • influxDB
  • ClickHouse
  • Linux
  • Docker
  • K8s
  • 消息队列
  • Shell
  • Git
  • Nginx
  • IDEA
  • Windows
  • 安卓
  • 在线工具
  • 实用技巧
  • 开源项目
  • 好文
  • 资源
  • 网站
  • 导航
💖关于
  • 分类
  • 标签
  • 归档

baohua.yin

不会填坑的程序员不是一个好程序猿!
🏠首页
  • 开发必备
  • Java
  • Spring Boot
  • MyBatis
  • C#
  • 架构
  • 算法
  • Vue
  • JavaScript
  • HTML
  • MySQL
  • Oracle
  • SQL Server
  • PostgreSQL
  • Redis
  • MongoDB
  • ElasticSearch
  • influxDB
  • ClickHouse
  • Linux
  • Docker
  • K8s
  • 消息队列
  • Shell
  • Git
  • Nginx
  • IDEA
  • Windows
  • 安卓
  • 在线工具
  • 实用技巧
  • 开源项目
  • 好文
  • 资源
  • 网站
  • 导航
💖关于
  • 分类
  • 标签
  • 归档
  • 提取和删除照片图片 Exif GPS 等隐私信息
    • Java调用CMD(Dos)命令
    • MultipartFile与File互转&inputStream转File
    • Alibaba Java 技术图谱
    • Java传给前端的Long类型字段要转为String类型
    • Java根据出生日期获取年龄
    • Java利用Hutool对身份证操作
    • java测试造数据神器JavaFaker
    • Sonar修复笔记
    • Java
    baohua.yin
    2023-03-03
    目录

    提取和删除照片图片 Exif GPS 等隐私信息

    # 照片图片 Exif

    通过手机相机或者数码相机拍摄的照片都带有 Exif 元数据信息,比如下面这张照片:

    它的 Exif 信息为:

    Root: 
    ImageWidth: 4000
    ImageLength: 3000
    Make: 'Xiaomi'
    Model: 'MI CC 9'
    Orientation: 1
    XResolution: 72
    YResolution: 72
    ResolutionUnit: 2
    DateTime: '2019:12:16 13:49:17'
    YCbCrPositioning: 1
    ExifOffset: 210
    GPSInfo: 770
    
    Exif: 
    ExposureTime: 1/295 (0.003)
    FNumber: 179/100 (1.79)
    PhotographicSensitivity: 112
    Unknown Tag (0x8895): 0
    ExifVersion: 48, 50, 50, 48
    DateTimeOriginal: '2019:12:16 13:49:17'
    DateTimeDigitized: '2019:12:16 13:49:17'
    ComponentsConfiguration: 1, 2, 3, 0
    ShutterSpeedValue: 8202/1000 (8.202)
    ApertureValue: 167/100 (1.67)
    ExposureCompensation: 0
    MaxApertureValue: 167/100 (1.67)
    MeteringMode: 2
    LightSource: 0
    Flash: 16
    FocalLength: 4740/1000 (4.74)
    SubSecTime: '646073'
    SubSecTimeOriginal: '646073'
    SubSecTimeDigitized: '646073'
    Unknown Tag (0x9999): '{"mirror":false,"sensor_type":"rear","Hdr":"off","OpMode":36869}'
    FlashpixVersion: 48, 49, 48, 48
    ColorSpace: 1
    ExifImageWidth: 4000
    ExifImageLength: 3000
    InteropOffset: 738
    SensingMethod: 1
    WhiteBalance: 0
    FocalLengthIn35mmFormat: 25
    
    Interoperability: 
    InteroperabilityIndex: 'R98'
    InteroperabilityVersion: 48, 49, 48, 48
    
    Gps: 
    GPSLatitudeRef: 'N'
    GPSLatitude: 40, 21, 401435/10000 (40.144)
    GPSLongitudeRef: 'E'
    GPSLongitude: 116, 1, 14916/10000 (1.492)
    GPSAltitudeRef: 0
    GPSAltitude: 722801/1000 (722.801)
    GPSTimeStamp: 5, 49, 12
    GPSProcessingMethod: 'GPS'
    GPSDateStamp: '2019:12:16'
    

    我们可以看到该照片是在 2019-12-16 13:49:17 通过小米 CC 9 拍摄,并且可以看到经纬度海拔等信息。

    如果没有去除 Exif 里的敏感信息,那么发布到网络上后,任何人都可以查看 Exif 信息,在某些情况下会造成隐私泄露。

    # Java 操作 Exif

    我们可通过 Apache Commons Imaging 来读取和写入 Exif 元数据。

    1、引入依赖 commons-imaging

    <dependency>
       <groupId>org.apache.commons</groupId>
       <artifactId>commons-imaging</artifactId>
       <version>1.0-alpha1</version>
    </dependency>
    

    2、读取 Exif

    final ImageMetadata metadata = Imaging.getMetadata(bytes);
    final JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;
    final TiffImageMetadata exif = jpegMetadata.getExif();
    

    3、写入 Exif

    final TiffOutputSet outputSet = exif.getOutputSet();
    new ExifRewriter().updateExifMetadataLossless(bytes, os, outputSet);
    

    # Java 删除敏感 Exif

    两种删除 Exif 信息的方法

    第一种比较暴力,通过图片字节数组中 Exif 标识开头和结尾来完整擦除整个 Exif 段

    public static byte[] removeExif(final byte[] bytes) {
        try {
            final byte b0 = bytes[0];
            final byte b1 = bytes[1];
            if (-1 != b0 || -40 != b1) { // FF D8
                return bytes; // not jpeg
            }
    
            if (-1 != bytes[2] || -31 != bytes[3]) { // exif seg: FF E1
                return bytes; // no exif
            }
    
            String len0 = Integer.toHexString(bytes[4]);
            if (2 > len0.length()) {
                len0 = "0" + len0;
            } else {
                len0 = len0.substring(len0.length() - 2);
            }
            String len1 = Integer.toHexString(bytes[5]);
            if (2 > len1.length()) {
                len1 = "0" + len1;
            } else {
                len1 = len1.substring(len1.length() - 2);
            }
            final String lenStr = len0 + "" + len1;
            final int len = Integer.parseInt(lenStr, 16);
            final byte[] ret = new byte[bytes.length - len - 4 - 2];
            ret[0] = -1;
            ret[1] = -40;
            System.arraycopy(bytes, 4 + len, ret, 2, ret.length - 2);
            return ret;
        } catch (final Exception e) {
            LOGGER.log(Level.ERROR, "Removes Exif failed", e);
            return bytes;
        }
      }
    

    该方法的优点是性能很好,但缺点就是会擦除 Exif 中有用的信息(比如方向 Orientation,如果没有该字段,那么浏览器就无法自动旋转图片为正常方向了。

    另一个方法是通过上面介绍的 commons-imaging 来删除,这样可以保留想要的字段:

    public static byte[] removeExif(final byte[] bytes) throws Exception {
        try (final ByteArrayOutputStream os = new ByteArrayOutputStream()) {
            TiffOutputSet outputSet = null;
            final ImageMetadata metadata = Imaging.getMetadata(bytes);
            if (!(metadata instanceof JpegImageMetadata)) {
                return bytes;
            }
    
            final JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata;
            final TiffImageMetadata exif = jpegMetadata.getExif();
            if (null != exif) {
                outputSet = exif.getOutputSet();
            }
    
            if (null == outputSet) {
                return bytes;
            }
    
            final List<TiffOutputDirectory> directories = outputSet.getDirectories();
            for (final TiffOutputDirectory directory : directories) {
                final List<TiffOutputField> fields = directory.getFields();
                for (final TiffOutputField field : fields) {
                    if (!StringUtils.equalsIgnoreCase("Orientation", field.tagInfo.name)) {
                        outputSet.removeField(field.tagInfo);
                    }
                }
            }
    
            new ExifRewriter().updateExifMetadataLossless(bytes, os, outputSet);
            return os.toByteArray();
        }
    }
    
    上次更新: 2023/06/02, 10:22:12
    Java调用CMD(Dos)命令

    Java调用CMD(Dos)命令→

    最近更新
    01
    如何进行科学上网
    05-31
    02
    分享(一个外地女孩,死在了我出租的公寓)
    08-18
    03
    温家宝总理—《我的母亲》
    06-13
    更多文章>
    Copyright © 2019-2025 1024fuli.com | 本站所有资源收集整理于网络,如有侵权请发邮件联系删除。| 粤ICP备18082936号-1 | 由又拍云提供CDN支持
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式