WPF 通过 EXIF 设置和读取图片的旋转信息
本文将告诉大家如何在 WPF 里面设置图片的 EXIF 信息,包括如何设置图片的旋转信息,以及如何读取 EXIF 的内容
值得一提的是在 WPF 里面,默认的图片渲染信息是无视 System.Photo.Orientation 信息的,一切都是推荐进行手动控制
在开始之前,咱先来用代码创建一张简单的图片
在 WPF 里面,使用代码进行绘图是一个非常高性能的方法,可以重复使用 DirectX 提供的高性能绘制能力,再加上 WPF 特别友好的 API 进行绘制。而且 WPF 的上层 API 是统一的,屏蔽掉很多细节,不需要更多额外的知识即可使用
先创建一个 DrawingVisual 对象,在这里面传入想要绘制的内容,接着使用 RenderTargetBitmap 存放为图片,最后再使用编码器生成图片
以下是创建 DrawingVisual 进行简单绘制的代码
var drawingVisual = new DrawingVisual();
using (var drawingContext = drawingVisual.RenderOpen())
{
drawingContext.DrawRectangle(Brushes.White, null, new Rect(new Size(100, 10)));
drawingContext.DrawLine(new Pen(Brushes.Black, 2), new Point(2, 5), new Point(90, 5));
}
这里先绘制一个矩形是为了撑开范围,作为画布大小
以上代码准确来说,是没有进行任何实际的绘制逻辑,只是告诉 WPF 框架,应该如何进行绘制。那啥时候才能进行绘制?需要在实际用到绘制的时候,才会调用 DirectX 进行绘制,例如调用 RenderTargetBitmap 的 Render 方法,将绘制的指令转换为绘制为内存的图片
var dpiScale = VisualTreeHelper.GetDpi(this);
var renderTargetBitmap = new RenderTargetBitmap(100, 10, dpiScale.PixelsPerInchX, dpiScale.PixelsPerInchY,
PixelFormats.Pbgra32);
renderTargetBitmap.Render(drawingVisual);
想要将内存里的图片存放到文件里面,就需要先对此按照一定的规则进行编码,例如本文将使用 Jpg 编码
先新建编码器
var jpegBitmapEncoder = new JpegBitmapEncoder();
接着传入 RenderTargetBitmap 用来编码
var bitmapFrame = BitmapFrame.Create(renderTargetBitmap);
jpegBitmapEncoder.Frames.Add(bitmapFrame);
最后输出为文件
var file = Path.GetTempFileName() + ".jpg";
using (var fileStream = new FileStream(file, FileMode.Create, FileAccess.ReadWrite))
{
jpegBitmapEncoder.Save(fileStream);
}
在 BitmapFrame 的创建代码里,可以指定 BitmapMetadata 用来设置 EXIF 信息,例如创建了以下的 BitmapMetadata 对象
var bitmapMetadata = new BitmapMetadata("jpg")
{
Title = "旋转的图片",
Author = new ReadOnlyCollection<string>(new[] { "林德熙" }),
Comment = "这是备注",
Copyright = "版权",
Subject = "主题",
ApplicationName = "应用",
};
那么从保存的图片的属性即可拿到上面传入的内容

本文所需要的旋转信息,也是设置到 BitmapMetadata 内容,使用 SetQuery 方法进行设置
const int Rotate90 = 6;
bitmapMetadata.SetQuery("System.Photo.Orientation", Rotate90);
除了这个旋转信息,能写入属性有哪些,写入的类型是什么?这些可以从 官方文档 获取
以下就是全部的创建图片的代码
var drawingVisual = new DrawingVisual();
using (var drawingContext = drawingVisual.RenderOpen())
{
drawingContext.DrawRectangle(Brushes.White, null, new Rect(new Size(100, 10)));
drawingContext.DrawLine(new Pen(Brushes.Black, 2), new Point(2, 5), new Point(90, 5));
}
var dpiScale = VisualTreeHelper.GetDpi(this);
var renderTargetBitmap = new RenderTargetBitmap(100, 10, dpiScale.PixelsPerInchX, dpiScale.PixelsPerInchY,
PixelFormats.Pbgra32);
renderTargetBitmap.Render(drawingVisual);
var jpegBitmapEncoder = new JpegBitmapEncoder();
var bitmapMetadata = new BitmapMetadata("jpg")
{
Title = "旋转的图片",
Author = new ReadOnlyCollection<string>(new[] { "林德熙" }),
Comment = "这是备注",
Copyright = "版权",
Subject = "主题",
ApplicationName = "应用",
};
const int Rotate90 = 6;
bitmapMetadata.SetQuery("System.Photo.Orientation", Rotate90);
var bitmapFrame = BitmapFrame.Create(renderTargetBitmap, thumbnail: null, bitmapMetadata,
new ReadOnlyCollection<ColorContext>(new List<ColorContext>()));
jpegBitmapEncoder.Frames.Add(bitmapFrame);
var file = Path.GetTempFileName() + ".jpg";
using (var fileStream = new FileStream(file, FileMode.Create, FileAccess.ReadWrite))
{
jpegBitmapEncoder.Save(fileStream);
}
接下来在 XAML 放一个 Image 控件,设置图片文件给图片控件,可以看到图片控件是无视 System.Photo.Orientation 的内容
Image.Source = new BitmapImage(new Uri(file));
接下来尝试读取解析图片的 EXIF 信息,获取到旋转角度
先进行解码,从本地文件获取到图片文件,需要将图片文件解码,才能在内存里面认识这个图片
var decoder = BitmapDecoder.Create
(
new Uri(file, UriKind.Absolute),
BitmapCreateOptions.DelayCreation,
BitmapCacheOption.None
);
为了性能考虑,这里只是读取 EXIF 信息,就设置了 DelayCreation 标记,如此就不会全部解析图片的内容
获取 BitmapFrame 内容
var frame = decoder.Frames[0];
接着读取 BitmapMetadata 信息
const string query = "System.Photo.Orientation";
return frame.Metadata is BitmapMetadata bitmapMetadata
&& bitmapMetadata.ContainsQuery(query)
&& bitmapMetadata.GetQuery(query) is ushort orientation
? orientation switch
{
6 => Rotation.Rotate90,
3 => Rotation.Rotate180,
8 => Rotation.Rotate270,
_ => Rotation.Rotate0,
}
: Rotation.Rotate0;
根据旋转角度,可以获取到显示的尺寸
var size = rotation is Rotation.Rotate90 or Rotation.Rotate270
? new Size(frame.PixelHeight, frame.PixelWidth)
: new Size(frame.PixelWidth, frame.PixelHeight);
全部的读取代码如下
private void Decode(string file)
{
var decoder = BitmapDecoder.Create
(
new Uri(file, UriKind.Absolute),
BitmapCreateOptions.DelayCreation,
BitmapCacheOption.None
);
var frame = decoder.Frames[0];
var rotation = GetRotation(frame);
var size = rotation is Rotation.Rotate90 or Rotation.Rotate270
? new Size(frame.PixelHeight, frame.PixelWidth)
: new Size(frame.PixelWidth, frame.PixelHeight);
}
private Rotation GetRotation(BitmapFrame frame)
{
const string query = "System.Photo.Orientation";
return frame.Metadata is BitmapMetadata bitmapMetadata
&& bitmapMetadata.ContainsQuery(query)
&& bitmapMetadata.GetQuery(query) is ushort orientation
? orientation switch
{
6 => Rotation.Rotate90,
3 => Rotation.Rotate180,
8 => Rotation.Rotate270,
_ => Rotation.Rotate0,
}
: Rotation.Rotate0;
}
可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin aee84bc738984fe0df51bea703ace2e721f9ec99
以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin aee84bc738984fe0df51bea703ace2e721f9ec99
获取代码之后,进入 HurcadahejaiYawhekurji 文件夹
在 UWP 里,写入 EXIF 信息,请参阅 UWP 写入图片 Exif 信息
WPF 通过 EXIF 设置和读取图片的旋转信息的更多相关文章
- WPF Image Source 设置相对路径图片
BitmapImage bt = new BitmapImage(new Uri("Images\\3_u10484.png", UriKind.Relative));this.I ...
- 用C#读取图片的EXIF信息的方法
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Dr ...
- Android中读取图片EXIF元数据之metadata-extractor的使用
一.引言及介绍 近期在开发中用到了metadata-extractor-xxx.jar 和 xmpcore-xxx.jar这个玩意, 索性查阅大量文章了解学习,来分享分享. 本身工作也是常常和处理大图 ...
- WPF 后台C#设置控件背景图片
原文:WPF 后台C#设置控件背景图片 以前的程序中有做过,当时只是记得uri很长一大段就没怎么记.今天有人问了也就写下来. 这是一个Button,设置了Background后的效果. 前台的设置 ...
- Java读取图片exif信息实现图片方向自动纠正
起因 一个对试卷进行OCR识别需求,需要实现一个功能,一个章节下的题目图片需要上下拼接合成一张大图,起初写了一个工具实现图片的合并,程序一直很稳定的运行着,有一反馈合成的图片方向不对,起初怀疑是本身图 ...
- 用WPF窗体打造个性化界面的图片浏览器
原文:用WPF窗体打造个性化界面的图片浏览器 本文使用WPF窗体(XAML及C#)与Win Form控件(FolderBrowserDialog)结合的方式, 演示制作了一个简易漂亮的WPF图片浏览器 ...
- python 修改、读取图片元数据
图片元数据 图片元数据(metadata)是嵌入到图片文件中的一些标签.比较像文件属性,但是种类繁多.常见的几种标准有: EXIF:通常被数码相机在拍摄照片时自动添加,比如相机型号.镜头.曝光.图片尺 ...
- HTML中上传与读取图片或文件(input file)----在路上(25)
input file相关知识简例 在此介绍的input file相关知识为: 上传照片及文件,其中包括单次上传.批量上传.删除照片.增加照片.读取图片.对上传的图片或文件的判断,比如限制图片的张数.限 ...
- python 读取图片的尺寸、分辨率
#需要安装PIL模块 #encoding=gbk#--------------------------------------------------------------------------- ...
- OpenGL——OpenCV与SOIL读取图片进行纹理贴图
使用OpenCV读取图片代码如下 img = imread(m_fileName); if (img.empty()) { fprintf(stderr, "Can not load ima ...
随机推荐
- 记录--vue中使用vue-video-player实现直播推流播放m3u8
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 1.安装 vue-video-player npm install vue-video-player --save npm install ...
- 安全测试系列:《web安全深度剖析》读书笔记
一 基础 1.http请求流程: 请求.响应报文格式: 8种请求方式,get(长度有限制).head(用于测试资源是否存在,服务器不返回消息主体).post(传输大量数据).put(给服务器上传资源) ...
- cyc_to_led
Entity: cyc_to_led File: cyc_to_led.v Diagram Generics Generic name Type Value Description MD_SIM_AB ...
- WARN o.a.t.util.scan.StandardJarScanner - Failed to scan [file:/D:/Mavencangku/com/sun/xml/bind/jaxb-core/2.3.0/jaxb-api.jar] from classloader hierarchy
1.SpringBoot项目启动突然报错 2024-03-27 14:57:41 [restartedMain] WARN o.a.t.util.scan.StandardJarScanner - F ...
- 22 axios和axios拦截器
1. axios 由于jquery有严重的地狱回调逻辑. 再加上jquery的性能逐年跟不上市场节奏. 很多前端工程师采用axios来发送ajax. 相比jquery. axios更加灵活. 且容易使 ...
- Codeforces Round #726 (Div. 2)
CF1537A Arithmetic Array 洛谷传送门 CF1537A 分析 用这 \(n\) 个数的总和 \(sum\) 判断: 如果 \(sum<n\) 直接用 \(n-sum+1\) ...
- #双指针#洛谷 7405 [JOI 2021 Final] 雪玉
题目传送门 分析 无论怎样刮风,雪球的相对位置不会改变, 实际上每一个空段都由左右两个雪球瓜分(边界空段除外), 那么按照空段长度从小到大排序,用双指针找到恰好第一个未瓜分的位置 代码 #includ ...
- CSP2019-S2总结
目录 前言 洛谷 5657 格雷码 代码(找规律) 洛谷 5658 括号树 分析 代码 洛谷 5659 树上的数 洛谷 5664 Emiya 家今天的饭 洛谷 5665 划分 分析 代码 洛谷 566 ...
- 使用 GitLab CI/CD 和阿里云 CLI 自动部署前端项目
一.什么是 CI/CD? CI(持续交付)是功能迭代后自动构建.打包.校验代码格式.跑单测.单测覆盖率,常见的就是 Webpack.Rollup.ESLint等. CD(持续部署)是经过 CI 后,代 ...
- CMake 构建指南:如何提高 C/C++ 项目的可维护性
如果您是一位C/C++开发人员,那么您一定知道在编写和维护大型项目时所面临的挑战.这些项目通常包含大量的源代码.库和依赖项,需要耗费大量的时间和精力才能构建和维护.在这种情况下,使用自动化工具可以大大 ...