c#使用ExifLib库提取图像的相机型号、光圈、快门、iso、曝光时间、焦距信息等EXIF信息

news2024/9/20 18:48:59

近期公司组织了书画摄影比赛,本人作为摄影爱好者,平时也会拍些照片,这次比赛当然不能错过。为了提高获奖概率,选了19张图像作为参赛作品。但是,摄影作品要提交图像的光圈、曝光时间等参数。一两张还可以通过电脑自带软件右键查看图像参数并一个个复制,但现在有19张,让我一点点复制还不如直接放弃参与了。谁让咱们还有一个身份是coder,那就现场手撸个小程序批量输出图像的EXIF信息。

开发需求很简单,就是能手动选取一个文件夹,然后读取该路径下的所有文件(图片),然后提取每张图像的exif信息,并将结果显示到界面,然后将Ctrl + A复制所有信息即可。在开发上,语言选择c#,搭配WPF框架,并选择ExifLib这个轻量化的EXIF信息提取库获取图像参数信息,下图是最终的提取信息。
在这里插入图片描述
XAML主要代码

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="auto"/>
        </Grid.RowDefinitions>
        <TextBox x:Name="textBox" Grid.Row="0"/>
        <Button Content="请选择一个路径"  Click="Button_Click"  Grid.Row="1" Background="LightBlue" Margin="2,0,2,2" Padding="5" />
    </Grid>

cs逻辑代码:

		using ExifLib;

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            // 创建一个选择文件路径的对话框
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Multiselect = false;
            openFileDialog.CheckFileExists = false;
            openFileDialog.FileName = "Folder Selection.";
            openFileDialog.Filter = "Folders|no.files";

            Dictionary<string, string> dic_pathAndName = new Dictionary<string, string>();
            if (openFileDialog.ShowDialog() == true)
            {
                string folderPath = System.IO.Path.GetDirectoryName(openFileDialog.FileName);

                // 使用 DirectoryInfo 类获取该路径下的所有文件
                DirectoryInfo directoryInfo = new DirectoryInfo(folderPath);
                FileInfo[] fileInfos = directoryInfo.GetFiles();

                // 处理获取到的文件
                foreach (FileInfo fileInfo in fileInfos)
                {
                    Debug.WriteLine(fileInfo.Name);
                    //dic_pathAndName[System.IO.Path.GetFileNameWithoutExtension(fileInfo.FullName)] = fileInfo.FullName;//key为没有后缀名的文件名
                    dic_pathAndName[fileInfo.Name] = fileInfo.FullName;
                }
            }

            if (dic_pathAndName.Count == 0) return;

            foreach (var dic in dic_pathAndName)
            {
                Debug.WriteLine($"{dic.Key}:  {getImageExifInfo(dic.Value)}");
                textBox.AppendText($"{dic.Key}, {getImageExifInfo(dic.Value)}\n");
            }



        }

        string getImageExifInfo(string path)
        {
            if (!File.Exists(path)) return "";

            string res = "";
            try
            {
                using (ExifReader reader = new ExifReader(path))
                {
                    // 相机制造商
                    if (reader.GetTagValue(ExifTags.Make, out string make))
                        Debug.WriteLine("相机制造商: " + make);

                    // 相机型号
                    if (reader.GetTagValue(ExifTags.Model, out string model))
                        Debug.WriteLine("相机型号: " + model);

                    // 光圈
                    if (reader.GetTagValue(ExifTags.FNumber, out double fNumber))
                    {
                        var fNumberFraction = FractionFromDouble(fNumber);
                        Debug.WriteLine("光圈: F/" + fNumber);
                    }

                    string time = "";
                    // 快门速度
                    if (reader.GetTagValue(ExifTags.ExposureTime, out double exposureTime))
                    {
                        var exposureTimeFraction = FractionFromDouble(exposureTime);
                        time = exposureTimeFraction.Item1 + "/" + exposureTimeFraction.Item2;
                    }

                    // ISO
                    if (reader.GetTagValue(ExifTags.ISOSpeedRatings, out ushort isoSpeedRatings))
                        Debug.WriteLine("ISO: " + isoSpeedRatings);

                     曝光时间
                    //if (reader.GetTagValue(ExifTags.ExposureTime, out double exposureTime))
                    //    Debug.WriteLine("曝光时间: " + exposureTime.ToString("0.##") + " s");

                    // 焦距
                    if (reader.GetTagValue(ExifTags.FocalLength, out double focalLength))
                        Debug.WriteLine("焦距: " + focalLength.ToString("0.##") + " mm");

                    res = $"{model} f/{fNumber} {time}s ISO-{isoSpeedRatings} {focalLength}mm";

                }

            }
            catch (Exception e)
            {

            }



            return res;
        }

        private Tuple<int, int> FractionFromDouble(double value, double error = 0.0001)
        {
            int denominator = 1;
            while (Math.Abs(value * denominator - Math.Round(value * denominator)) > error)
                denominator++;

            return Tuple.Create((int)Math.Round(value * denominator), denominator);
        }

以上代码直接复制、拷贝走,然后可以根据自己的需求输出想要的图像参数信息,并随意定义文本格式,爽歪歪。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1132797.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1024程序员节获奖名单公示~恭喜各位上榜同学

1024程序员节完美收官&#xff01; 恭喜各个分会场中奖的小伙伴~我们已于昨日的线下会场完成奖品及证书发放&#xff01; 更多优秀作品欢迎大家点击查看&#xff1a;卡奥斯开源社区 — 打造工业互联网顶级开源社区 颁奖典礼精彩回放&#xff1a;卡奥斯开源社区 — 打造工业互…

【ARM Coresight 系列文章 3.3 - ARM Coresight SWD 协议详细介绍】

文章目录 1.1 SWD 协议框图1.2 读/写时序及命令1.2.1 SWD 时序1.2.2 SWD 命令详情1.3 芯片探测1.3.1 获取芯片 ID1.4 读/写操作1.1 SWD 协议框图 SWD协议可以配置SoC内部几乎所有的寄存器。时钟信号由SWCLK 管脚输入,数据信号从SWDIO管脚输入输出。首先 HOST 对SW-DP 进行操作…

基于html5+javascript技术开发的房贷利率计算器

房贷计算器是一款专为购房者设计的实用工具应用&#xff0c;其主要功能是帮助用户详细计算房贷的还款金额、利息以及还款计划等。通过这款软件&#xff0c;用户可以更加便捷地了解到自己的还款情况和计划&#xff0c;从而更好地规划自己的财务。下面将对房贷计算器进行详细的介…

基于PHP的图像分享社交平台

有需要请加文章底部Q哦 可远程调试 基于PHP的图像分享社交平台 一 介绍 此图像分享社交平台基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端bootstrap。平台角色分为用户和管理员。用户可注册登录&#xff0c;发布图像&#xff0c;修改个人信息&#xff0c;评论图像…

家电翻页电子画册制作秘籍,轻松打造炫酷电子书!

在家电市场上&#xff0c;翻页电子画册已经成为了越来越多人的选择。它不仅具有传统纸质画册的优点&#xff0c;还具有更多的功能和特点&#xff0c;如翻页动画、音效等&#xff0c;让阅读变得更加有趣和生动。那么&#xff0c;如何制作一款炫酷的电子画册呢&#xff1f;今天就…

国产 87235系列USB平均功率探头

频率范围覆盖 功率测量准确度&#xff1a;0.2dB 10MHz&#xff5e;50GHz 87235系列 USB平均功率探头是一款基于USB 2.0接口的二极管检波式高精度、大动态范围平均功率测量仪器&#xff0c;可实现各种格式信号平均功率的准确测量。87235系列平均功率探头频率范围覆盖10MHz&am…

Spring Boot整合OAuth2实现GitHub第三方登录

Spring Boot整合OAuth2&#xff0c;实现GitHub第三方登录 1、第三方登录原理 第三方登录的原理是借助OAuth授权来实现&#xff0c;首先用户先向客户端提供第三方网站的数据证明自己的身份获取授权码&#xff0c;然后客户端拿着授权码与授权服务器建立连接获得一个Access Token…

【Note】链式存储结构

设计不同的结点结构&#xff0c;可以构成不同的链式存储结构。常用的有&#xff1a;二叉链表、三叉链表、线索链表&#xff08;用空链域存放指向前驱或后继的线索&#xff09;。 二叉链表存储 VS 一般二叉树 二叉链表 VS 二叉树 知识点&#xff1a; 一个二叉链表由根指针root…

2022年06月 Python(一级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python等级考试&#xff08;1~6级&#xff09;全部真题・点这里 一、单选题&#xff08;共25题&#xff0c;每题2分&#xff0c;共50分&#xff09; 第1题 在Python编辑器中写好程序代码后&#xff0c;在Run菜单中&#xff0c;下列哪个命令可以用来执行程序&#xff1f;&…

消费大变革时代,三只松鼠的“高端性价比”如何突围制胜?

在浙江1天连开37家社区零食店&#xff0c;三只松鼠正在苏醒。 “三只松鼠去年是重创&#xff0c;可以讲是壮士断腕。”三只松鼠&#xff08;300783.SZ&#xff09;创始人、CEO章燎原在9月底接受红星资本局专访时总结。 过去几年&#xff0c;章燎原几乎没有接受过媒体采访。而…

计算机基础知识39

外键 外键字段>>>:部门编号 其实就是用来标识表与表之间的数据关系 # 简单的理解为该字段可以让你去到其他表中查找数据 表与表之间的关系 # 一对多、多对多、一对一、没有关系 ### 一对多的表关系&#xff1a; 员工表&#xff1a;一个员工一个部门 x …

如何使用 Pinia ORM 管理 Vue 中的状态

状态管理是构建任何Web应用程序的重要组成部分。虽然Vue提供了管理简单状态的技术&#xff0c;但随着应用程序复杂性的增加&#xff0c;处理状态可能变得更具挑战性。这就是为什么像Pinia这样的库被创建出来&#xff0c;以增强Vue的基本状态管理能力。然而&#xff0c;在大型应…

uni-app中tab选项卡的实现效果 @click=“clickTab(‘sell‘)“事件可传参数

一、效果图 二、代码 <template><view><view class"choose-tab"><view class"choose-tab-item" :class"chooseTab 0 ? active : " data-choose"0" click"clickTab">选项1</view><view …

第三天:配置+运行代码+改个保存键

1.上午 11点前 1.拉取文件 刷新依赖库看代码改需求 2.上午11点后 解决问题如下2.1 2.2 看文档看代码 3.下午2点到6点 对接前端 看演示视频看代码把软件运行起来 4.一直报错 &#xff08;依赖环境装备配比&#xff09; 5.依赖文件一直报错&#xff08;一会好 一会错&…

项目团队管理的常见难点,如何有效解决?

在项目管理中&#xff0c;项目经理经常会遇到团队成员工作不积极、工作任务互相推诿、踢皮球以及习惯性甩锅等一系列的团队管理相关的问题&#xff1b;遭遇这几大常见问题后&#xff0c;项目推进就容易陷入僵局。在这种情况下&#xff0c;如何有效解决问题&#xff0c;提升工作…

Pytorch整体工作流程代码详解(新手入门)

一、前言 本文详细介绍Pytorch的基本工作流程及代码&#xff0c;以及如何在GPU上训练模型&#xff08;如下图所示&#xff09;包括数据准备、模型搭建、模型训练、评估及模型的保存和载入。 适用读者&#xff1a;有一定的Python和机器学习基础的深度学习/Pytorch初学者。 本文…

HDR和泛光

HDR 显示器被限制为只能显示值为0.0到1.0间的颜色&#xff0c;但是在光照方程中却没有这个限制。通过使片段的颜色超过1.0&#xff0c;我们有了一个更大的颜色范围&#xff0c;这也被称作HDR(High Dynamic Range, 高动态范围) 允许用更大范围的颜色值渲染从而获取大范围的黑暗…

APP盾的防御机制及应用场景

移动应用&#xff08;APP&#xff09;在我们日常生活中扮演着越来越重要的角色&#xff0c;但随之而来的是各种网络安全威胁的增加。为了保障APP的安全性&#xff0c;APP盾作为一种专门设计用于防御移动应用威胁的工具得以广泛应用。本文将深入探讨APP盾的防御机制以及在不同应…

计算机算法分析与设计(20)---回溯法(0-1背包问题)

文章目录 1. 题目描述2. 算法思路3. 例题分析4. 代码编写 1. 题目描述 对于给定的 n n n 个物品&#xff0c;第 i i i 个物品的重量为 W i W_i Wi​&#xff0c;价值为 V i V_i Vi​&#xff0c;对于一个最多能装重量 c c c 的背包&#xff0c;应该如何选择放入包中的物品…

命令行输入sns.countplot(data[‘marital‘])报错

代码sns.countplot(data[marital])是用于绘制柱状图来显示分类变量的频数分布。但是&#xff0c;根据警告信息&#xff0c;从Seaborn 0.12版本开始&#xff0c;只有一个有效的位置参数data&#xff0c;其他参数必须作为关键字参数传递。因此&#xff0c;你需要将参数data[marit…