Repository: Cryolitia/PhotoTimeFix
Branch: main
Commit: d51d3ed7aefa
Files: 34
Total size: 144.1 KB
Directory structure:
gitextract_d81n_rbi/
├── .gitignore
├── PhotoTimeFix/
│ ├── App.xaml
│ ├── App.xaml.cs
│ ├── PhotoTimeFix.csproj
│ ├── Properties/
│ │ └── launchSettings.json
│ ├── Resource/
│ │ ├── Resource.Designer.cs
│ │ ├── Resource.resx
│ │ ├── Resource.zh-Hans.resx
│ │ └── Resource.zh-Hant.resx
│ ├── Util/
│ │ ├── DefaultFileProcessor.cs
│ │ ├── FileExistValidationRule.cs
│ │ ├── IFileProcessor.cs
│ │ ├── ProcessResult.cs
│ │ ├── ProcessResultList.cs
│ │ ├── SettingItemAttribute.cs
│ │ └── ThemeHelper.cs
│ ├── ViewBinding/
│ │ ├── MainWindowBinding.cs
│ │ └── SettingBinding.cs
│ ├── Window/
│ │ ├── CodeEditWindow.xaml
│ │ ├── CodeEditWindow.xaml.cs
│ │ ├── ImageWindow.xaml
│ │ ├── ImageWindow.xaml.cs
│ │ ├── MainWindow.xaml
│ │ ├── MainWindow.xaml.cs
│ │ ├── ProcessBarWindow.xaml
│ │ ├── ProcessBarWindow.xaml.cs
│ │ ├── ProcessWindow.xaml
│ │ └── ProcessWindow.xaml.cs
│ └── app.manifest
├── PhotoTimeFix.sln
├── README.md
└── WapProject/
├── .gitignore
├── Package.appxmanifest
└── WapProject.wapproj
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
*.pfx
================================================
FILE: PhotoTimeFix/App.xaml
================================================
================================================
FILE: PhotoTimeFix/App.xaml.cs
================================================
using System;
using System.Globalization;
using System.Threading.Tasks;
using System.Windows;
using Microsoft.AppCenter;
using Microsoft.AppCenter.Analytics;
using Microsoft.AppCenter.Crashes;
namespace PhotoTimeFix
{
///
/// Interaction logic for App.xaml
///
public partial class App : Application
{
#if DEBUG
public static readonly bool IsDebug = true;
#else
public static readonly bool IsDebug = false;
#endif
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
if (!IsDebug)
{
//UI线程未捕获异常处理事件
DispatcherUnhandledException += (sender, e1) =>
{
MessageBox.Show(e1.Exception.Message);
Crashes.TrackError(e1.Exception);
};
//Task线程内未捕获异常处理事件
TaskScheduler.UnobservedTaskException += (sender, e1) =>
{
MessageBox.Show(e1.Exception.Message);
Crashes.TrackError(e1.Exception);
};
//非UI线程未捕获异常处理事件
AppDomain.CurrentDomain.UnhandledException += delegate(object sender, UnhandledExceptionEventArgs args)
{
var ex = args.ExceptionObject;
if (ex is Exception)
{
MessageBox.Show((ex as Exception).Message);
Crashes.TrackError(ex as Exception);
}
};
//System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US");
//System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
var countryCode = RegionInfo.CurrentRegion.TwoLetterISORegionName;
AppCenter.SetCountryCode(countryCode);
AppCenter.Start("5aa5aa14-0bd1-45f1-bea4-72d960c9c576", typeof(Crashes), typeof(Analytics));
}
}
}
}
================================================
FILE: PhotoTimeFix/PhotoTimeFix.csproj
================================================
WinExe
net48
true
True
a9ikq-xzp6j-001.ico
PhotoTimeFix.App
Cryolitia
Github
https://github.com/Cryolitia/PhotoTimeFix
Copyright 2018-Now Cryolitia
README.md
照片时间修复.jpg
https://github.com/Cryolitia/PhotoTimeFix
true
false
..\cert.pfx
disable
README.md
AnyCPU
true
1.3.3
en;zh-Hans;zh-Hant
app.manifest
1.3.3
embedded
true
True
\
cert.pfx
True
\
M2.NSudo.dll
True
True
Resource.resx
True
True
Resource.resx
PublicResXFileCodeGenerator
Resource.Designer.cs
PublicResXFileCodeGenerator
PublicResXFileCodeGenerator
PublicResXFileCodeGenerator
Resource.Designer.cs
PublicResXFileCodeGenerator
PublicResXFileCodeGenerator
Always
Always
Always
Always
Always
Always
Always
================================================
FILE: PhotoTimeFix/Properties/launchSettings.json
================================================
{
"profiles": {
"PhotoTimeFix": {
"commandName": "Project"
}
}
}
================================================
FILE: PhotoTimeFix/Resource/Resource.Designer.cs
================================================
//------------------------------------------------------------------------------
//
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
//
//------------------------------------------------------------------------------
namespace PhotoTimeFix.Resource {
using System;
///
/// 一个强类型的资源类,用于查找本地化的字符串等。
///
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class Resource {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resource() {
}
///
/// 返回此类使用的缓存的 ResourceManager 实例。
///
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PhotoTimeFix.Resource.Resource", typeof(Resource).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
///
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
///
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
///
/// 查找类似 Author: 的本地化字符串。
///
public static string About_Author {
get {
return ResourceManager.GetString("About_Author", resourceCulture);
}
}
///
/// 查找类似 Cryolitia 的本地化字符串。
///
public static string About_Neuron {
get {
return ResourceManager.GetString("About_Neuron", resourceCulture);
}
}
///
/// 查找类似 Open Source License 的本地化字符串。
///
public static string About_OpenSourceLicense {
get {
return ResourceManager.GetString("About_OpenSourceLicense", resourceCulture);
}
}
///
/// 查找类似 Github repo: 的本地化字符串。
///
public static string About_OpenSourceLink {
get {
return ResourceManager.GetString("About_OpenSourceLink", resourceCulture);
}
}
///
/// 查找类似 Telegram: 的本地化字符串。
///
public static string About_Telegram {
get {
return ResourceManager.GetString("About_Telegram", resourceCulture);
}
}
///
/// 查找类似 Thanks to all open source software contributors for going forward 的本地化字符串。
///
public static string About_ThanksToOpenSource {
get {
return ResourceManager.GetString("About_ThanksToOpenSource", resourceCulture);
}
}
///
/// 查找类似 Photo Time Fix 的本地化字符串。
///
public static string App_Name {
get {
return ResourceManager.GetString("App_Name", resourceCulture);
}
}
///
/// 查找类似 Compile 的本地化字符串。
///
public static string CodeEditWindow_Compile {
get {
return ResourceManager.GetString("CodeEditWindow_Compile", resourceCulture);
}
}
///
/// 查找类似 Compiled successfully 的本地化字符串。
///
public static string CodeEditWindow_CompileSuccess {
get {
return ResourceManager.GetString("CodeEditWindow_CompileSuccess", resourceCulture);
}
}
///
/// 查找类似 Current creation time: 的本地化字符串。
///
public static string MainWindow_CurrentCreationTime {
get {
return ResourceManager.GetString("MainWindow_CurrentCreationTime", resourceCulture);
}
}
///
/// 查找类似 Current last write time: 的本地化字符串。
///
public static string MainWindow_CurrentModificationTime {
get {
return ResourceManager.GetString("MainWindow_CurrentModificationTime", resourceCulture);
}
}
///
/// 查找类似 Current user: 的本地化字符串。
///
public static string MainWindow_CurrentUser {
get {
return ResourceManager.GetString("MainWindow_CurrentUser", resourceCulture);
}
}
///
/// 查找类似 Current user group: 的本地化字符串。
///
public static string MainWindow_CurrentUserGroup {
get {
return ResourceManager.GetString("MainWindow_CurrentUserGroup", resourceCulture);
}
}
///
/// 查找类似 Custom filename parser 的本地化字符串。
///
public static string MainWindow_CustomFileProcessingClass {
get {
return ResourceManager.GetString("MainWindow_CustomFileProcessingClass", resourceCulture);
}
}
///
/// 查找类似 File Name 的本地化字符串。
///
public static string MainWindow_FileName {
get {
return ResourceManager.GetString("MainWindow_FileName", resourceCulture);
}
}
///
/// 查找类似 File System Metadata 的本地化字符串。
///
public static string MainWindow_FileSystem {
get {
return ResourceManager.GetString("MainWindow_FileSystem", resourceCulture);
}
}
///
/// 查找类似 File or folder path 的本地化字符串。
///
public static string MainWindow_FolderFilePath {
get {
return ResourceManager.GetString("MainWindow_FolderFilePath", resourceCulture);
}
}
///
/// 查找类似 New Time: 的本地化字符串。
///
public static string MainWIndow_NewTime {
get {
return ResourceManager.GetString("MainWIndow_NewTime", resourceCulture);
}
}
///
/// 查找类似 Run As Admin 的本地化字符串。
///
public static string MainWindow_RunAsAdmin {
get {
return ResourceManager.GetString("MainWindow_RunAsAdmin", resourceCulture);
}
}
///
/// 查找类似 Run As Trust Installer 的本地化字符串。
///
public static string MainWindow_RunAsTrustInstaller {
get {
return ResourceManager.GetString("MainWindow_RunAsTrustInstaller", resourceCulture);
}
}
///
/// 查找类似 Start 的本地化字符串。
///
public static string MainWindow_Start {
get {
return ResourceManager.GetString("MainWindow_Start", resourceCulture);
}
}
///
/// 查找类似 Open Log File 的本地化字符串。
///
public static string ProcessWindow_Copy {
get {
return ResourceManager.GetString("ProcessWindow_Copy", resourceCulture);
}
}
///
/// 查找类似 Detail 的本地化字符串。
///
public static string ProcessWindow_Detail {
get {
return ResourceManager.GetString("ProcessWindow_Detail", resourceCulture);
}
}
///
/// 查找类似 File 的本地化字符串。
///
public static string ProcessWindow_File {
get {
return ResourceManager.GetString("ProcessWindow_File", resourceCulture);
}
}
///
/// 查找类似 New Time 的本地化字符串。
///
public static string ProcessWindow_NewTime {
get {
return ResourceManager.GetString("ProcessWindow_NewTime", resourceCulture);
}
}
///
/// 查找类似 Status 的本地化字符串。
///
public static string ProcessWindow_Status {
get {
return ResourceManager.GetString("ProcessWindow_Status", resourceCulture);
}
}
///
/// 查找类似 Path should not be empty 的本地化字符串。
///
public static string Rule_PathNonNull {
get {
return ResourceManager.GetString("Rule_PathNonNull", resourceCulture);
}
}
///
/// 查找类似 Path not exist 的本地化字符串。
///
public static string Rule_PathNotExist {
get {
return ResourceManager.GetString("Rule_PathNotExist", resourceCulture);
}
}
///
/// 查找类似 Process only media files 的本地化字符串。
///
public static string Setting_MediaOnly {
get {
return ResourceManager.GetString("Setting_MediaOnly", resourceCulture);
}
}
///
/// 查找类似 Only process files with MIME type "image/*" or "video/*" when batch processing 的本地化字符串。
///
public static string Setting_MediaOnlySummary {
get {
return ResourceManager.GetString("Setting_MediaOnlySummary", resourceCulture);
}
}
///
/// 查找类似 Open media 的本地化字符串。
///
public static string Setting_OpenMedia {
get {
return ResourceManager.GetString("Setting_OpenMedia", resourceCulture);
}
}
///
/// 查找类似 Prefer EXIF 的本地化字符串。
///
public static string Setting_PreferExif {
get {
return ResourceManager.GetString("Setting_PreferExif", resourceCulture);
}
}
///
/// 查找类似 Try to read EXIF tag firstly 的本地化字符串。
///
public static string Setting_PreferExifSummary {
get {
return ResourceManager.GetString("Setting_PreferExifSummary", resourceCulture);
}
}
///
/// 查找类似 Safe mode 的本地化字符串。
///
public static string Setting_SafeMode {
get {
return ResourceManager.GetString("Setting_SafeMode", resourceCulture);
}
}
///
/// 查找类似 Prevent time from being set before 1970 or after the current time 的本地化字符串。
///
public static string Setting_SafeModeSummary {
get {
return ResourceManager.GetString("Setting_SafeModeSummary", resourceCulture);
}
}
///
/// 查找类似 Save Log file 的本地化字符串。
///
public static string Setting_SaveLog {
get {
return ResourceManager.GetString("Setting_SaveLog", resourceCulture);
}
}
///
/// 查找类似 This operation will attempt to manipulate the file itself and write the EXIF tag, which may cause irrecoverable damage to the file. Please back up before proceeding! 的本地化字符串。
///
public static string Warning_EXIF {
get {
return ResourceManager.GetString("Warning_EXIF", resourceCulture);
}
}
}
}
================================================
FILE: PhotoTimeFix/Resource/Resource.resx
================================================
text/microsoft-resx
2.0
System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Author:
Cryolitia
Open Source License
Github repo:
Thanks to all open source software contributors for going forward
Photo Time Fix
Compile
Current creation time:
Current last write time:
Current user:
Current user group:
Custom filename parser
File or folder path
New Time:
Run As Admin
Run As Trust Installer
Start
Path should not be empty
Path not exist
Telegram:
Safe mode
Compiled successfully
File
Status
New Time
Detail
Prevent time from being set before 1970 or after the current time
Prefer EXIF
Try to read EXIF tag firstly
Process only media files
Only process files with MIME type "image/*" or "video/*" when batch processing
Open media
Open Log File
Save Log file
File Name
File System Metadata
This operation will attempt to manipulate the file itself and write the EXIF tag, which may cause irrecoverable damage to the file. Please back up before proceeding!
================================================
FILE: PhotoTimeFix/Resource/Resource.zh-Hans.resx
================================================
text/microsoft-resx
2.0
System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
照片时间修复
文件或文件夹路径
当前创建时间
当前修改时间
新时间:
自定义文件名解析方法
开始
当前用户:
当前用户组:
以管理员权限运行
以Trust Installer权限运行
作者:
神经元/Cryolitia
开源地址:
开放源代码许可
感谢所有开源软件的贡献者们的一往无前
编译
路径不应为空
路径不存在
安全模式
编译成功
文件
状态
新时间
细节
阻止将时间设置为1970年之前或当前时间之后
EXIF优先
优先尝试读取EXIF信息
仅处理媒体文件
批处理时仅处理MIME类型为"image/*"或"video/*"的文件
打开媒体
打开日志文件
保存日志文件
文件名
文件系统元数据
该操作会尝试操作文件本身并写入EXIF标签,可能造成文件不可恢复的损坏,请先备份再进行操作!
================================================
FILE: PhotoTimeFix/Resource/Resource.zh-Hant.resx
================================================
text/microsoft-resx
2.0
System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
照片時間修復
檔案或資料夾路徑
當前建立時間
當前修改時間
新時間:
自定義檔名解析方法
開始
當前使用者:
當前使用者組:
以管理員許可權執行
以Trust Installer許可權執行
作者:
神經元/Cryolitia
開源地址:
開放原始碼許可
感謝所有開源軟體的貢獻者們的一往無前
編譯
路徑不應為空
路徑不存在
安全模式
編譯成功
檔案
狀態
新時間
細節
阻止將時間設定為1970年之前或當前時間之後
EXIF優先
優先嚐試讀取EXIF資訊
僅處理媒體檔案
批處理時僅處理MIME型別為"image/*"或"video/*"的檔案
開啟媒體
開啟日誌檔案
儲存日誌檔案
檔案名稱
檔案系統元資料
該操作會嘗試操作檔案本身並寫入EXIF標籤,可能造成檔案不可恢復的損壞,請先備份再進行操作!
================================================
FILE: PhotoTimeFix/Util/DefaultFileProcessor.cs
================================================
using System;
using System.Globalization;
using System.IO;
using System.Text.RegularExpressions;
using PhotoTimeFix.Util;
public class DefaultFileProcessor : IFileProcessor {
private const string regexString =
"(19|20)[0-9]{2}[^0-9]*?(0[1-9]|1[0-2])[^0-9]*?([0-2][0-9]|[3][0-1])[^0-9]*?([01][0-9]|2[0-3])[^0-9]*?[0-5][0-9][^0-9]*?[0-5][0-9]";
private static Regex regex = new Regex(regexString, RegexOptions.Compiled);
private static Regex regex2 = new Regex(@"\d{13}", RegexOptions.Compiled);
private static Regex regex3 = new Regex(@"\d{10}", RegexOptions.Compiled);
private static Regex spaceRemover = new Regex(@"\D+", RegexOptions.Compiled);
public DateTime? GetFileDateTime(FileInfo fileInfo)
{
var mathch = regex.Match(fileInfo.Name);
if (mathch.Success)
{
string result = mathch.Value;
result = spaceRemover.Replace(result, "");
return DateTime.ParseExact(result, "yyyyMMddHHmmss", CultureInfo.InvariantCulture);
}
else
{
var match2 = regex2.Match(fileInfo.Name);
Int64 result2 = -1;
if (match2.Success)
{
result2 = Int64.Parse(match2.Value)/1000;
} else
{
var match3 = regex3.Match(fileInfo.Name);
if (match3.Success)
{
result2 = Int64.Parse(match3.Value);
}
}
if (result2!=-1)
{
return TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)).AddSeconds(result2);
}
else
{
return null;
}
}
}
}
================================================
FILE: PhotoTimeFix/Util/FileExistValidationRule.cs
================================================
using System.Globalization;
using System.IO;
using System.Windows.Controls;
namespace PhotoTimeFix.Util
{
public class FileExistValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
if (value == null || string.IsNullOrWhiteSpace((value ?? "").ToString()))
return new ValidationResult(false, Resource.Resource.Rule_PathNonNull);
var path = value.ToString();
return File.Exists(path) || Directory.Exists(path)
? ValidationResult.ValidResult
: new ValidationResult(false, Resource.Resource.Rule_PathNotExist);
}
}
}
================================================
FILE: PhotoTimeFix/Util/IFileProcessor.cs
================================================
using System;
using System.IO;
namespace PhotoTimeFix.Util
{
public interface IFileProcessor
{
DateTime? GetFileDateTime(FileInfo fileInfo);
}
}
================================================
FILE: PhotoTimeFix/Util/ProcessResult.cs
================================================
namespace PhotoTimeFix.Util
{
public class ProcessResult
{
public ProcessResult(string mFileName, string mDateTime, string mStatus, string mDetail)
{
FileName = mFileName;
DateTime = mDateTime;
Status = mStatus;
Detail = mDetail;
}
public string FileName { get; set; }
public string DateTime { get; set; }
public string Status { get; set; }
public string Detail { get; set; }
}
}
================================================
FILE: PhotoTimeFix/Util/ProcessResultList.cs
================================================
using System.Collections.ObjectModel;
namespace PhotoTimeFix.Util
{
public class ProcessResultList : ObservableCollection
{
public void Add(string mFileName, string mDateTime, string mStatus, string mDetail)
{
Add(new ProcessResult(mFileName, mDateTime, mStatus, mDetail));
}
}
}
================================================
FILE: PhotoTimeFix/Util/SettingItemAttribute.cs
================================================
using System;
using System.Windows.Forms;
namespace PhotoTimeFix.Util
{
[AttributeUsage(AttributeTargets.Property)]
public class SettingItemAttribute : Attribute
{
public SettingItemAttribute(string name, string summary)
{
Name = name;
Summary = summary;
}
public SettingItemAttribute(string res)
{
try
{
Name = typeof(Resource.Resource).GetProperty("Setting_" + res).GetValue(null) as string;
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
try
{
Summary = typeof(Resource.Resource).GetProperty("Setting_" + res+ "Summary").GetValue(null) as string;
}
catch (Exception e)
{
//ignore
}
}
public string Name { get; set; }
public string Summary { get; set; }
}
}
================================================
FILE: PhotoTimeFix/Util/ThemeHelper.cs
================================================
using System;
using System.Text;
using System.Windows;
using System.Windows.Media;
using Windows.Foundation.Metadata;
using Windows.UI.ViewManagement;
using MaterialDesignThemes.Wpf;
using Microsoft.Win32;
namespace PhotoTimeFix.Util
{
public static class ThemeHelper
{
private static bool eventInitial;
//https://kira-96.github.io/posts/%E5%A6%82%E4%BD%95%E8%8E%B7%E5%8F%96Windows10%E4%B8%BB%E9%A2%98%E9%A2%9C%E8%89%B2/
public static void InitTheme()
{
var paletteHelper = new PaletteHelper();
var isLight = true;
try
{
var registryValue =
Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize",
"AppsUseLightTheme", null);
isLight = Convert.ToBoolean(registryValue);
}
catch (Exception exception)
{
MessageBox.Show(exception.ToString());
}
var theme = new Theme();
if (isLight)
theme.SetLightTheme();
else
theme.SetDarkTheme();
var color = isLight ? Color.FromRgb(66, 133, 244) : Color.FromRgb(130, 168, 231);
theme.SetPrimaryColor(color);
RequireSystemTheme(theme, isLight);
if (!eventInitial)
{
SystemEvents.UserPreferenceChanged += (sender, args) => { InitTheme(); };
eventInitial = true;
}
paletteHelper.SetTheme(theme);
}
public static void RequireSystemTheme(Theme theme, bool isLight)
{
try
{
#pragma warning disable CA1416 // 验证平台兼容性
if (ApiInformation.IsTypePresent("Windows.UI.ViewManagement.UISettings"))
{
var uiSettings = new UISettings();
var accentColor = uiSettings.GetColorValue(UIColorType.Accent);
theme.SetPrimaryColor(Color.FromRgb(accentColor.R, accentColor.G, accentColor.B));
theme.SetSecondaryColor(Color.FromRgb(accentColor.R, accentColor.G, accentColor.B));
if (!isLight)
{
theme.Cards.Background = Color.FromRgb(18, 18, 18);
theme.Background = Colors.Black;
}
}
#pragma warning restore CA1416 // 验证平台兼容性
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
public static void ShowSystemColor()
{
var uiSettings = new UISettings();
var builder = new StringBuilder();
builder.Append("System Colors: " + '\n');
foreach (UIColorType type in Enum.GetValues(typeof(UIColorType)))
if (type != UIColorType.Complement)
builder.Append(type + ": " + uiSettings.GetColorValue(type) + '\n');
builder.Append('\n');
foreach (UIElementType type in Enum.GetValues(typeof(UIElementType)))
builder.Append(type + ": " + uiSettings.UIElementColor(type) + '\n');
System.Windows.Forms.MessageBox.Show(builder.ToString());
}
}
}
================================================
FILE: PhotoTimeFix/ViewBinding/MainWindowBinding.cs
================================================
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Windows;
using CSScriptLib;
using ICSharpCode.AvalonEdit.Document;
using PhotoTimeFix.Util;
namespace PhotoTimeFix.ViewBinding
{
public class MainWindowBinding : INotifyPropertyChanged
{
private IEnumerable _detailTags;
private string _filePath;
private IFileProcessor _fileProcessor;
private TextDocument _fileProcessorCode;
private Visibility _isFile = Visibility.Collapsed;
private DateTime? _nowDate;
private DateTime? _nowTime;
private Visibility _pathExist = Visibility.Collapsed;
public bool IsDebug => App.IsDebug;
public string FilePath
{
get => _filePath;
set
{
_filePath = value;
OnPropertyChanged(nameof(FilePath));
}
}
public Visibility IsFile
{
get => _isFile;
set
{
_isFile = value;
OnPropertyChanged(nameof(IsFile));
OnPropertyChanged(nameof(StartEnabled));
}
}
public Visibility PathExist
{
get => _pathExist;
set
{
_pathExist = value;
OnPropertyChanged(nameof(PathExist));
OnPropertyChanged(nameof(StartEnabled));
}
}
public IEnumerable DetailTags
{
get => _detailTags;
set
{
_detailTags = value;
OnPropertyChanged(nameof(DetailTags));
}
}
public DateTime? NowDate
{
get => _nowDate;
set
{
_nowDate = value;
OnPropertyChanged(nameof(NowDate));
OnPropertyChanged(nameof(StartEnabled));
}
}
public DateTime? NowTime
{
get => _nowTime;
set
{
_nowTime = value;
OnPropertyChanged(nameof(NowTime));
OnPropertyChanged(nameof(StartEnabled));
}
}
public bool StartEnabled => NowDate != null && NowTime != null && IsFile == Visibility.Visible ||
IsFile == Visibility.Collapsed && PathExist == Visibility.Visible;
public TextDocument FileProcessorCode
{
get
{
if (_fileProcessorCode == null)
{
var assembly = Assembly.GetExecutingAssembly();
var stream =
assembly.GetManifestResourceStream(assembly.GetName().Name + ".Util.DefaultFileProcessor.cs");
var reader = new StreamReader(stream);
_fileProcessorCode = new TextDocument(reader.ReadToEnd());
_fileProcessorCode.SetOwnerThread(Application.Current.Dispatcher.Thread);
}
return _fileProcessorCode;
}
set
{
_fileProcessorCode = value;
OnPropertyChanged(nameof(FileProcessorCode));
}
}
public IFileProcessor FileProcessor
{
get
{
if (_fileProcessor == null)
{
var code = Application.Current.Dispatcher.Invoke(() => FileProcessorCode.Text);
_fileProcessor = (IFileProcessor) CSScript.Evaluator.LoadCode(code);
}
return _fileProcessor;
}
set => _fileProcessor = value;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
================================================
FILE: PhotoTimeFix/ViewBinding/SettingBinding.cs
================================================
using System.ComponentModel;
using System.Runtime.CompilerServices;
using PhotoTimeFix.Util;
namespace PhotoTimeFix.ViewBinding
{
public class SettingBinding : INotifyPropertyChanged
{
private bool _onlyMedia = true;
private bool _safetyMode = true;
private bool _showMedia = false;
private bool _saveLog = false;
[SettingItem("SafeMode")]
public bool SafetyMode
{
get => _safetyMode;
set
{
_safetyMode = value;
OnPropertyChanged(nameof(SafetyMode));
}
}
[SettingItem("MediaOnly")]
public bool OnlyMedia
{
get => _onlyMedia;
set
{
_onlyMedia = value;
OnPropertyChanged(nameof(OnlyMedia));
}
}
[SettingItem("OpenMedia")]
public bool ShowMedia
{
get => _showMedia;
set
{
_showMedia = value;
OnPropertyChanged(nameof(ShowMedia));
}
}
[SettingItem("SaveLog")]
public bool SaveLog
{
get => _saveLog;
set
{
_saveLog = value;
OnPropertyChanged(nameof(SaveLog));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
================================================
FILE: PhotoTimeFix/Window/CodeEditWindow.xaml
================================================
================================================
FILE: PhotoTimeFix/Window/CodeEditWindow.xaml.cs
================================================
using System;
using System.Windows;
using CSScriptLib;
using PhotoTimeFix.Util;
using PhotoTimeFix.ViewBinding;
namespace PhotoTimeFix.Window
{
public partial class CodeEditWindow : System.Windows.Window
{
private MainWindowBinding _binding;
public CodeEditWindow()
{
InitializeComponent();
}
public MainWindowBinding Binding
{
set => _binding = value;
}
private async void Compile_OnClick(object sender, RoutedEventArgs e)
{
try
{
var code = CodeEditor.Text;
await ProcessBarWindow.StartTask(action =>
{
_binding.FileProcessor = (IFileProcessor) CSScript.Evaluator.LoadCode(code);
MessageBox.Show(Resource.Resource.CodeEditWindow_CompileSuccess);
action.Invoke();
});
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
================================================
FILE: PhotoTimeFix/Window/ImageWindow.xaml
================================================
================================================
FILE: PhotoTimeFix/Window/ImageWindow.xaml.cs
================================================
using System;
using System.IO;
using System.Windows.Media.Imaging;
namespace PhotoTimeFix.Window
{
///
/// ImageWindow.xaml 的交互逻辑
///
public partial class ImageWindow : System.Windows.Window
{
public ImageWindow(string path)
{
InitializeComponent();
Title = new FileInfo(path).Name;
ImageView.Source = new BitmapImage(new Uri(path));
}
}
}
================================================
FILE: PhotoTimeFix/Window/MainWindow.xaml
================================================
https://github.com/Cryolitia/PhotoTimeFix
某元的原神頻道
================================================
FILE: PhotoTimeFix/Window/MainWindow.xaml.cs
================================================
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Forms;
using DesktopBridge;
using ICSharpCode.AvalonEdit;
using LicensesDialog;
using LicensesDialog.Licenses;
using M2.NSudo;
using MetadataExtractor;
using MetadataExtractor.Formats.Exif;
using MimeTypes;
using PhotoTimeFix.Util;
using PhotoTimeFix.ViewBinding;
using Application = System.Windows.Forms.Application;
using Binding = System.Windows.Data.Binding;
using CheckBox = System.Windows.Controls.CheckBox;
using DataFormats = System.Windows.DataFormats;
using Directory = System.IO.Directory;
using DragDropEffects = System.Windows.DragDropEffects;
using DragEventArgs = System.Windows.DragEventArgs;
using Image = System.Drawing.Image;
using Label = System.Windows.Controls.Label;
using MessageBox = System.Windows.MessageBox;
using OpenFileDialog = Microsoft.Win32.OpenFileDialog;
namespace PhotoTimeFix.Window
{
///
/// Interaction logic for MainWindow.xaml
///
public partial class MainWindow : System.Windows.Window
{
private readonly MainWindowBinding _binding;
private readonly SettingBinding _setting;
private Dictionary _exifInfos = new Dictionary();
public MainWindow()
{
InitializeComponent();
_binding = (MainWindowBinding)Resources[nameof(MainWindowBinding)];
ThemeHelper.InitTheme();
InitUser();
_setting = new SettingBinding();
InitSetting();
}
private Dictionary ExifInfos
{
get => _exifInfos;
set
{
_exifInfos = value;
_binding.DetailTags = value.Keys;
DetailTextBox.Text = "";
}
}
private void InitUser()
{
var identity = WindowsIdentity.GetCurrent();
UserNameText.Content = identity.Name;
var principal = new WindowsPrincipal(identity);
var wbirFields = Enum.GetValues(typeof(WindowsBuiltInRole));
var groups = "";
foreach (WindowsBuiltInRole roleName in wbirFields)
if (principal.IsInRole(roleName))
groups += roleName.ToString() + '\n';
GroupText.Content = groups;
var windowsPrincipal = new WindowsPrincipal(identity);
if (new Helpers().IsRunningAsUwp())
{
RunAsAdminButton.Visibility = Visibility.Collapsed;
RunAsTrustInstallerButton.Visibility = Visibility.Collapsed;
}
else if (windowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator))
{
RunAsAdminButton.Visibility = Visibility.Collapsed;
}
else
{
RunAsTrustInstallerButton.Visibility = Visibility.Collapsed;
}
}
private void InitSetting()
{
var i = 0;
foreach (var info in typeof(SettingBinding).GetProperties())
{
var attribute = info.GetCustomAttribute();
if (attribute != null)
{
var label = new Label();
label.Content = attribute.Name;
label.ToolTip = attribute.Summary;
label.Margin = new Thickness(5, 5, 0, 5);
var button = new ToggleButton();
button.IsChecked = (bool)info.GetValue(_setting);
button.Style = (Style)FindResource("MaterialDesignSwitchToggleButton");
button.Margin = new Thickness(0, 5, 5, 5);
var binding = new Binding(info.Name);
binding.Source = _setting;
button.SetBinding(ToggleButton.IsCheckedProperty, binding);
SettingContainer.RowDefinitions.Add(new RowDefinition());
SettingContainer.Children.Add(label);
SettingContainer.Children.Add(button);
Grid.SetColumn(label, 0);
Grid.SetRow(label, i);
Grid.SetColumn(button, 1);
Grid.SetRow(button, i);
i++;
}
}
}
private void FileButton_OnClick(object sender, RoutedEventArgs e)
{
var dialog = new OpenFileDialog();
if (dialog.ShowDialog() ?? false) _binding.FilePath = dialog.FileName;
}
private void DictionaryButton_OnClick(object sender, RoutedEventArgs e)
{
var dialog = new FolderBrowserDialog();
if (dialog.ShowDialog().Equals(System.Windows.Forms.DialogResult.OK))
_binding.FilePath = dialog.SelectedPath;
}
private void Grid_OnLayoutUpdated(object sender, EventArgs e)
{
var height = DetailCard.ActualHeight - DetailListBox.ActualHeight - 30d;
if (height > 0) DetailTextBox.Height = height;
var minWidth = Panel1.ActualWidth + Panel2.ActualWidth + 30d;
var minHeight = SelectCard.ActualHeight + Math.Max(Panel1.ActualHeight, Panel2.ActualHeight) + 60d;
if (DetailCard.Visibility == Visibility.Visible) minWidth += 480d;
MinWidth = minWidth;
MinHeight = minHeight;
}
private async void PathTextBox_OnTextChanged(object sender, TextChangedEventArgs e)
{
var value = PathTextBox.Text;
if (File.Exists(value))
{
await ProcessBarWindow.StartTask(action =>
{
Dispatcher.Invoke(async () =>
{
await UpdateCurrentTime(true, action);
if (File.Exists(value))
{
_binding.IsFile = Visibility.Visible;
_binding.PathExist = Visibility.Visible;
await UpdateExif(value);
DetailListBox.SelectAll();
if (_setting.ShowMedia) ShowImage(value);
}
});
});
}
else
{
if (Directory.Exists(value))
_binding.PathExist = Visibility.Visible;
else
_binding.PathExist = Visibility.Collapsed;
_binding.IsFile = Visibility.Collapsed;
ExifInfos = new Dictionary();
DetailTextBox.Text = "";
}
}
private async Task UpdateCurrentTime(bool resetNow = true, Action action = null)
{
var path = PathTextBox.Text;
if (resetNow)
{
_binding.NowDate = null;
_binding.NowTime = null;
}
if (File.Exists(path))
{
var info = new FileInfo(path);
CurrentCreateTime.Text = info.CreationTime.ToString(CultureInfo.CurrentCulture);
CurrentModifyTime.Text = info.LastWriteTime.ToString(CultureInfo.CurrentCulture);
try
{
var dateTime = await TryGetDatetimeFromFile(info);
_binding.NowDate = dateTime;
_binding.NowTime = dateTime;
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
else
{
CurrentCreateTime.Text = "";
CurrentModifyTime.Text = "";
}
action?.Invoke();
}
private async Task UpdateExif(string path)
{
var dictionary = new Dictionary();
try
{
var directories = await Task.Run(() => ImageMetadataReader.ReadMetadata(path));
try
{
var subIfdDirectory = directories.OfType().FirstOrDefault();
if (subIfdDirectory?.TryGetDateTime(ExifDirectoryBase.TagDateTime, out var dateTime) == true)
{
_binding.NowDate = dateTime;
_binding.NowTime = dateTime;
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
foreach (var directory in directories)
{
var value = "";
foreach (var tag in directory.Tags) value += $"[{directory.Name}] {tag.Name} = {tag.Description}\n";
if (directory.HasError)
foreach (var error in directory.Errors)
value += $"ERROR: {error}\n";
var name = directory.Name;
var i = 2;
var exist = dictionary.ContainsKey(name);
while (dictionary.ContainsKey(name + "-" + i)) i++;
if (exist) name += "-" + i;
dictionary.Add(name, value);
}
}
catch (Exception e)
{
dictionary.Add("Error", e.ToString());
}
ExifInfos = dictionary;
}
private static void ShowImage(string path)
{
try
{
var image = Image.FromFile(path);
var imageWindow = new ImageWindow(path);
imageWindow.Show();
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
private void DetailListBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var value = "";
foreach (var info in ExifInfos)
if (DetailListBox.SelectedItems.Contains(info.Key))
value += info.Value;
DetailTextBox.Text = value;
}
private void RunAsAdmin_OnClick(object sender, RoutedEventArgs args)
{
var startInfo = new ProcessStartInfo();
startInfo.UseShellExecute = true;
startInfo.WorkingDirectory = Environment.CurrentDirectory;
startInfo.FileName = Application.ExecutablePath;
startInfo.Verb = "runas";
try
{
Process.Start(startInfo);
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
Close();
Application.Exit();
}
private void RunAsTrustInstaller_OnClick(object sender, RoutedEventArgs args)
{
try
{
var instance = new NSudoInstance();
instance.CreateProcess(
NSUDO_USER_MODE_TYPE.TRUSTED_INSTALLER,
NSUDO_PRIVILEGES_MODE_TYPE.ENABLE_ALL_PRIVILEGES,
NSUDO_MANDATORY_LABEL_TYPE.SYSTEM,
NSUDO_PROCESS_PRIORITY_CLASS_TYPE.NORMAL,
NSUDO_SHOW_WINDOW_MODE_TYPE.DEFAULT,
0,
true,
Application.ExecutablePath,
Environment.CurrentDirectory
);
Close();
Application.Exit();
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
}
private void Grid_DragEnter(object sender, DragEventArgs e)
{
var fileData = (Array)e.Data.GetData(DataFormats.FileDrop, true);
if (fileData != null && fileData.Length == 1)
{
e.Effects = DragDropEffects.Link;
e.Handled = true;
}
else
{
e.Effects = DragDropEffects.None;
}
}
private void Grid_Drop(object sender, DragEventArgs e)
{
try
{
var fileData = (Array)e.Data.GetData(DataFormats.FileDrop, true);
if (fileData != null)
{
var fileName = fileData.GetValue(0).ToString();
if (!string.IsNullOrWhiteSpace(fileName)) PathTextBox.Text = fileName;
e.Handled = true;
}
}
catch (Exception exception)
{
MessageBox.Show(exception.ToString());
}
}
private void Hyperlink_Click(object sender, RoutedEventArgs e)
{
var link = sender as Hyperlink;
Process.Start(new ProcessStartInfo
{
FileName = link?.NavigateUri.AbsoluteUri ?? throw new InvalidOperationException(),
UseShellExecute = true
});
}
private void OpenSourceLicense_Click(object sender, RoutedEventArgs e)
{
var noticeList = new List();
noticeList.Add(new Notice("PhotoTimeFix", "https://github.com/Cryolitia/PhotoTimeFix",
"Copyroght 2018-Now Cryolitia", new MITLicense()));
noticeList.Add(new Notice("MetadataExtractor", "https://github.com/drewnoakes/metadata-extractor-dotnet",
"Drew Noakes", new ApacheSoftwareLicense20()));
noticeList.Add(new Notice("Material Design In XAML Toolkit",
"https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit", "MaterialDesignInXAML",
new MITLicense()));
noticeList.Add(new Notice("AvalonEdit", "https://github.com/icsharpcode/AvalonEdit",
"Copyright (c) AvalonEdit Contributors", new MITLicense()));
noticeList.Add(new Notice("CS-Script", "https://github.com/oleg-shilo/cs-script",
"Copyright (c) 2018 oleg-shilo", new MITLicense()));
noticeList.Add(new Notice("MimeTypeMap", "https://github.com/samuelneff/MimeTypeMap",
"Copyright (c) 2014 Samuel Neff", new MITLicense()));
new LicensesDialog.LicensesDialog.Builder().SetNotices(noticeList).SetShowOwnLicense(true).Build().Show();
}
private async void EditCode_OnClick(object sender, RoutedEventArgs e)
{
await Dispatcher.BeginInvoke(new Action(() =>
{
var window = new CodeEditWindow();
var binding = new Binding("FileProcessorCode");
binding.Source = _binding;
window.CodeEditor.SetBinding(TextEditor.DocumentProperty, binding);
window.Binding = _binding;
window.ShowDialog();
}));
}
private async void Start_OnClick(object sender, RoutedEventArgs e)
{
var window = new ProcessWindow(_setting.SaveLog);
if (_setting.SaveLog)
{
var dialog = new SaveFileDialog();
dialog.Title = Resource.Resource.Setting_SaveLog;
dialog.OverwritePrompt = true;
dialog.CreatePrompt = true;
dialog.Filter = "Log File (*.csv)|*.csv";
if (dialog.ShowDialog() != System.Windows.Forms.DialogResult.OK) return;
window.LogFile = dialog.FileName;
}
await window.ShowDialogAsync();
if (File.Exists(_binding.FilePath) && _binding.NowDate.HasValue && _binding.NowTime.HasValue)
{
var result = await Task.Run(() => ProcessFile(new FileInfo(_binding.FilePath),
new DateTime(_binding.NowDate.Value.Year, _binding.NowDate.Value.Month,
_binding.NowDate.Value.Day,
_binding.NowTime.Value.Hour, _binding.NowTime.Value.Minute, _binding.NowTime.Value.Second)));
await Dispatcher.BeginInvoke(new Action(() => { window.ProcessResultList.Add(result); }));
await UpdateCurrentTime(false);
}
else if (Directory.Exists(_binding.FilePath))
{
await Task.Run(() => ProcessDirectory(new DirectoryInfo(_binding.FilePath), window.ProcessResultList));
}
await Dispatcher.BeginInvoke(new Action(() =>
{
window.Closable = true;
}));
}
private async void ProcessDirectory(DirectoryInfo info, ProcessResultList list)
{
try
{
foreach (var mInfo in info.GetDirectories()) ProcessDirectory(mInfo, list);
foreach (var mInfo in info.GetFiles())
try
{
var dateTime = await TryGetDatetimeFromFile(mInfo);
if (dateTime != null)
{
var result = ProcessFile(mInfo, dateTime.Value);
await Dispatcher.BeginInvoke(new Action(() => { list.Add(result); }));
}
else
{
await Dispatcher.BeginInvoke(new Action(() =>
{
list.Add(mInfo.FullName, "Null", "Skip", "");
}));
}
}
catch (Exception e)
{
await Dispatcher.BeginInvoke(new Action(() =>
{
list.Add(mInfo.FullName, "", "Error", e.Message);
}));
}
}
catch (Exception e)
{
await Dispatcher.BeginInvoke(new Action(() => { list.Add(info.FullName, "", "Error", e.Message); }));
}
}
private async Task TryGetDatetimeFromFile(FileInfo mInfo)
{
bool exifSource = Dispatcher.Invoke(() => { return ExifSourceCheck.IsChecked == true; });
bool fileNameSource = Dispatcher.Invoke(() => { return FileNameSourceCheck.IsChecked == true; });
bool fileSystemSource = Dispatcher.Invoke(() => { return FileSystemSourceCheck.IsChecked == true; });
IReadOnlyList directories = null;
DateTime? dateTime = null;
if (exifSource)
try
{
directories = ImageMetadataReader.ReadMetadata(mInfo.FullName);
foreach(var subIfdDirectory in directories)
{
if (subIfdDirectory?.TryGetDateTime(ExifDirectoryBase.TagDateTime, out var mDateTime) == true)
dateTime = mDateTime;
if (dateTime == null)
{
if (subIfdDirectory?.TryGetDateTime(ExifDirectoryBase.TagDateTimeOriginal, out var m2DateTime) == true)
dateTime = m2DateTime;
}
if (dateTime != null)
{
break;
}
}
}
catch (Exception e)
{
//ignore
}
if (fileNameSource && dateTime == null)
dateTime = await Task.Run(() =>
{
var processor = _binding.FileProcessor;
return processor.GetFileDateTime(mInfo);
});
if (fileSystemSource && dateTime == null)
{
dateTime = mInfo.CreationTime;
if (dateTime == null) dateTime = mInfo.LastWriteTime;
}
return dateTime;
}
private ProcessResult ProcessFile(FileInfo info, DateTime dateTime)
{
try
{
bool exifDest = Dispatcher.Invoke(() => { return ExifDestCheck.IsChecked == true; });
bool fileNameDest = Dispatcher.Invoke(() => { return FileNameDestCheck.IsChecked == true; });
bool fileSystemDest = Dispatcher.Invoke(() => { return FileSystemDestCheck.IsChecked == true; });
var mime = MimeTypeMap.GetMimeType(info.Extension).ToLower();
if (_setting.OnlyMedia && !mime.StartsWith("image/") && !mime.StartsWith("video/"))
return new ProcessResult(info.FullName, "", "Skip", "MINE unmatch: " + mime);
if (_setting.SafetyMode && (dateTime > DateTime.Now || dateTime < new DateTime(1970, 1, 1)))
return new ProcessResult(info.FullName, "", "Skip",
"Date unbelievable: " + dateTime.ToString(CultureInfo.CurrentCulture));
if (fileSystemDest)
{
info.CreationTime = dateTime;
info.LastWriteTime = dateTime;
}
if (exifDest)
{
var image = Image.FromFile(info.FullName);
// https://stackoverflow.com/questions/18820525/how-to-get-and-set-propertyitems-for-an-image
var item = (PropertyItem)FormatterServices.GetUninitializedObject(typeof(PropertyItem));
// https://learn.microsoft.com/zh-cn/windows/win32/gdiplus/-gdiplus-constant-property-item-descriptions#propertytagdatetime
item.Id = 0x0132;
// https://github.com/microsoft/win32metadata/blob/1ba2527a59da3f1c1b4809bb053d03f300af3c09/generation/WinSDK/RecompiledIdlHeaders/um/gdiplusimaging.h#L302
item.Type = 2;
item.Value = Encoding.ASCII.GetBytes(dateTime.ToString("yyyy:MM:dd HH:mm:ss"));
item.Len = item.Value.Length;
image.SetPropertyItem(item);
var name = info.DirectoryName + "\\new_" + info.Name;
if (fileNameDest)
name = info.DirectoryName + "\\" + dateTime.ToString("yyyy-MM-dd HHmmss") + info.Extension;
image.Save(name);
if (_binding.IsFile == Visibility)
Dispatcher.Invoke(() => { PathTextBox.Text = name; });
}
if (!exifDest && fileNameDest)
{
var name = info.DirectoryName + "\\" + dateTime.ToString("yyyy-MM-dd HHmmss") + " " + info.Name;
info.MoveTo(name);
if (_binding.IsFile == Visibility)
Dispatcher.Invoke(() => { PathTextBox.Text = name; });
}
return new ProcessResult(info.FullName, dateTime.ToString(CultureInfo.CurrentCulture), "Success", "");
}
catch (Exception e)
{
return new ProcessResult(info.FullName, "", "Error", e.Message);
}
}
private async void SourceDestPanel_Checked(object sender, RoutedEventArgs e)
{
if (ExifSourceCheck == null || ExifDestCheck == null || FileNameSourceCheck == null ||
FileNameDestCheck == null || FileSystemSourceCheck == null || FileSystemDestCheck == null) return;
if (sender is CheckBox)
{
var sender1 = sender as CheckBox;
if (sender1.Name == ExifSourceCheck.Name)
{
await ProcessSourceDestPanel(ExifSourceCheck, ExifDestCheck);
}
else if (sender1.Name == ExifDestCheck.Name)
{
MessageBox.Show(Resource.Resource.Warning_EXIF);
await ProcessSourceDestPanel(ExifDestCheck, ExifSourceCheck);
}
else if (sender1.Name == FileNameSourceCheck.Name)
{
await ProcessSourceDestPanel(FileNameSourceCheck, FileNameDestCheck);
}
else if (sender1.Name == FileNameDestCheck.Name)
{
await ProcessSourceDestPanel(FileNameDestCheck, FileNameSourceCheck);
}
else if (sender1.Name == FileSystemSourceCheck.Name)
{
await ProcessSourceDestPanel(FileSystemSourceCheck, FileSystemDestCheck);
}
else if (sender1.Name == FileSystemDestCheck.Name)
{
await ProcessSourceDestPanel(FileSystemDestCheck, FileSystemSourceCheck);
}
}
}
private async Task ProcessSourceDestPanel(CheckBox source, CheckBox dest)
{
switch (source.IsChecked)
{
case true:
{
if (dest.IsEnabled == false) return;
dest.IsEnabled = false;
dest.IsChecked = false;
break;
}
case false:
{
if (dest.IsEnabled) return;
dest.IsEnabled = true;
break;
}
}
await UpdateCurrentTime();
}
}
}
================================================
FILE: PhotoTimeFix/Window/ProcessBarWindow.xaml
================================================
================================================
FILE: PhotoTimeFix/Window/ProcessBarWindow.xaml.cs
================================================
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows;
namespace PhotoTimeFix.Window
{
public partial class ProcessBarWindow : System.Windows.Window
{
public bool Closable;
private ProcessBarWindow()
{
InitializeComponent();
}
public static async Task StartTask(Action action)
{
var window = new ProcessBarWindow();
try
{
await window.Dispatcher.BeginInvoke(new Func(async () => { await window.ShowDialogAsync(); }));
await Task.WhenAll(Task.Run(() =>
{
action.Invoke(() =>
{
window.Closable = true;
window.Dispatcher.BeginInvoke(new Action(window.Close));
});
}));
}
catch (Exception e)
{
MessageBox.Show(e.Message);
window.Close();
}
}
public async Task ShowDialogAsync()
{
await Task.Run(() => { Dispatcher.BeginInvoke(new Action(() => { ShowDialog(); })); });
}
protected override void OnClosing(CancelEventArgs e)
{
if (Closable)
base.OnClosing(e);
else
e.Cancel = true;
}
}
}
================================================
FILE: PhotoTimeFix/Window/ProcessWindow.xaml
================================================
================================================
FILE: PhotoTimeFix/Window/ProcessWindow.xaml.cs
================================================
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using MaterialDesignThemes.Wpf;
using PhotoTimeFix.Util;
namespace PhotoTimeFix.Window
{
public partial class ProcessWindow : System.Windows.Window
{
private bool _closable;
private FileStream _logFile;
private UTF8Encoding utF8Encoding = new UTF8Encoding();
Dictionary result = new Dictionary();
public ProcessWindow(bool saveFile)
{
InitializeComponent();
MaxHeight = SystemParameters.WorkArea.Height;
MaxWidth = SystemParameters.WorkArea.Width;
ProcessResultList.CollectionChanged += (sender, args) =>
{
if (args.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
StringBuilder builder = null;
foreach (var item in args.NewItems)
{
if (item is ProcessResult)
{
var item1 = item as ProcessResult;
if (result.ContainsKey(item1.Status))
{
result[item1.Status] += 1;
}
else
{
result[item1.Status] = 1;
}
builder = new StringBuilder();
builder.Append(item1.FileName);
if (item1.DateTime != "")
{
builder.Append("\t\t=>\t\t");
builder.Append(item1.DateTime);
}
}
}
Dispatcher.BeginInvoke(new Action(() => {
if (!Closable)
{
if (builder != null)
{
ProcessingNow.Content = builder.ToString();
}
}
else
{
StringBuilder builder1 = new StringBuilder();
foreach (var item in result)
{
builder1.Append(item.Key);
builder1.Append(": ");
builder1.Append(item.Value);
builder1.Append("\t\t");
}
ProcessingNow.Content = builder1.ToString();
}
}));
}
};
if (saveFile)
{
ProcessResultList.CollectionChanged += (sender, args) =>
{
if (args.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
var builder = new StringBuilder();
foreach (var item in args.NewItems)
{
if (item is ProcessResult)
{
var item1 = item as ProcessResult;
builder.Append(item1.FileName);
builder.Append(',');
builder.Append(item1.Status);
builder.Append(',');
builder.Append(item1.DateTime);
builder.Append(',');
builder.Append(item1.Detail);
builder.AppendLine();
}
}
try
{
byte[] bytes = utF8Encoding.GetBytes(builder.ToString());
_logFile.WriteAsync(bytes, 0, bytes.Length) ;
}
catch(Exception e)
{
//ignore
}
}
};
}
}
public string LogFile
{
set
{
_logFile = File.OpenWrite(value);
}
}
public bool Closable
{
get => _closable;
set
{
_closable = value;
ProgressBar.Visibility = value ? Visibility.Collapsed : Visibility.Visible;
ListView.Visibility = Visibility.Visible;
StringBuilder builder = new StringBuilder();
foreach(var item in result)
{
builder.Append(item.Key);
builder.Append(": ");
builder.Append(item.Value);
builder.Append("\t\t");
}
ProcessingNow.Content = builder.ToString();
if (_logFile != null)
{
try
{
_logFile.Dispose();
}
catch(Exception e)
{
//ignore
}
}
MessageBox.Show("OK");
}
}
public ProcessResultList ProcessResultList => FindResource("ProcessResultList") as ProcessResultList;
public async Task ShowDialogAsync()
{
await Task.Run(() => { Dispatcher.BeginInvoke(new Action(() => { ShowDialog(); })); });
}
protected override void OnClosing(CancelEventArgs e)
{
if (Closable)
base.OnClosing(e);
else
e.Cancel = true;
}
}
}
================================================
FILE: PhotoTimeFix/app.manifest
================================================
true
system
true
================================================
FILE: PhotoTimeFix.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.32112.339
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PhotoTimeFix", "PhotoTimeFix\PhotoTimeFix.csproj", "{CB9D52F9-1DEA-4A5F-97B9-B2B46C2F2125}"
EndProject
Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "WapProject", "WapProject\WapProject.wapproj", "{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|ARM = Debug|ARM
Debug|ARM64 = Debug|ARM64
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|ARM = Release|ARM
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CB9D52F9-1DEA-4A5F-97B9-B2B46C2F2125}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CB9D52F9-1DEA-4A5F-97B9-B2B46C2F2125}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CB9D52F9-1DEA-4A5F-97B9-B2B46C2F2125}.Debug|ARM.ActiveCfg = Debug|Any CPU
{CB9D52F9-1DEA-4A5F-97B9-B2B46C2F2125}.Debug|ARM.Build.0 = Debug|Any CPU
{CB9D52F9-1DEA-4A5F-97B9-B2B46C2F2125}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{CB9D52F9-1DEA-4A5F-97B9-B2B46C2F2125}.Debug|ARM64.Build.0 = Debug|Any CPU
{CB9D52F9-1DEA-4A5F-97B9-B2B46C2F2125}.Debug|x64.ActiveCfg = Debug|Any CPU
{CB9D52F9-1DEA-4A5F-97B9-B2B46C2F2125}.Debug|x64.Build.0 = Debug|Any CPU
{CB9D52F9-1DEA-4A5F-97B9-B2B46C2F2125}.Debug|x86.ActiveCfg = Debug|Any CPU
{CB9D52F9-1DEA-4A5F-97B9-B2B46C2F2125}.Debug|x86.Build.0 = Debug|Any CPU
{CB9D52F9-1DEA-4A5F-97B9-B2B46C2F2125}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CB9D52F9-1DEA-4A5F-97B9-B2B46C2F2125}.Release|Any CPU.Build.0 = Release|Any CPU
{CB9D52F9-1DEA-4A5F-97B9-B2B46C2F2125}.Release|ARM.ActiveCfg = Release|Any CPU
{CB9D52F9-1DEA-4A5F-97B9-B2B46C2F2125}.Release|ARM.Build.0 = Release|Any CPU
{CB9D52F9-1DEA-4A5F-97B9-B2B46C2F2125}.Release|ARM64.ActiveCfg = Release|Any CPU
{CB9D52F9-1DEA-4A5F-97B9-B2B46C2F2125}.Release|ARM64.Build.0 = Release|Any CPU
{CB9D52F9-1DEA-4A5F-97B9-B2B46C2F2125}.Release|x64.ActiveCfg = Release|Any CPU
{CB9D52F9-1DEA-4A5F-97B9-B2B46C2F2125}.Release|x64.Build.0 = Release|Any CPU
{CB9D52F9-1DEA-4A5F-97B9-B2B46C2F2125}.Release|x86.ActiveCfg = Release|Any CPU
{CB9D52F9-1DEA-4A5F-97B9-B2B46C2F2125}.Release|x86.Build.0 = Release|Any CPU
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Debug|ARM.ActiveCfg = Debug|ARM
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Debug|ARM.Build.0 = Debug|ARM
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Debug|ARM.Deploy.0 = Debug|ARM
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Debug|ARM64.ActiveCfg = Debug|ARM64
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Debug|ARM64.Build.0 = Debug|ARM64
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Debug|ARM64.Deploy.0 = Debug|ARM64
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Debug|x64.ActiveCfg = Debug|x64
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Debug|x64.Build.0 = Debug|x64
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Debug|x64.Deploy.0 = Debug|x64
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Debug|x86.ActiveCfg = Debug|x86
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Debug|x86.Build.0 = Debug|x86
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Debug|x86.Deploy.0 = Debug|x86
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Release|Any CPU.Build.0 = Release|Any CPU
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Release|Any CPU.Deploy.0 = Release|Any CPU
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Release|ARM.ActiveCfg = Release|ARM
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Release|ARM.Build.0 = Release|ARM
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Release|ARM.Deploy.0 = Release|ARM
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Release|ARM64.ActiveCfg = Release|ARM64
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Release|ARM64.Build.0 = Release|ARM64
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Release|ARM64.Deploy.0 = Release|ARM64
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Release|x64.ActiveCfg = Release|x64
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Release|x64.Build.0 = Release|x64
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Release|x64.Deploy.0 = Release|x64
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Release|x86.ActiveCfg = Release|x86
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Release|x86.Build.0 = Release|x86
{A662AFBB-D12B-4B79-AEC8-C85F430ADD7D}.Release|x86.Deploy.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F90C5A59-1D30-4824-AFD3-2824C966DD53}
EndGlobalSection
EndGlobal
================================================
FILE: README.md
================================================
# PhotoTimeFix (WPF)



一个简单的小程序以通过文件名(或Exif)修复照片/屏幕截图的时间错误
An easy program aimed to fix photo's timestamp incorrect by filename/Exif
您是否曾经在备份照片后面对整齐划一的时间戳变成了今天的成千上万张照片不知所措?快来试试吧,这个软件可以通过文件名和文件中的Exif数据来恢复文件的时间戳,还支持自定义精确时间和批处理。永久开源免费!
* 现代的Material Design界面设计,自动适应系统主题(仅支持Windows 10 1903+)
* 自动尝试解析文件名和Exif信息
* 丰富的Exif元数据查看
* 完整的C#脚本支持,图灵完备的语言让您可以以任何自己想要的方式处理照片
* 内置NSudo,允许您两键即可最高以 `Trust Installer` 权限运行
* 完全永久的开源免费



================================================
FILE: WapProject/.gitignore
================================================
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
================================================
FILE: WapProject/Package.appxmanifest
================================================
PhotoTimeFix
Cryolitia
Images\StoreLogo.png
================================================
FILE: WapProject/WapProject.wapproj
================================================
15.0
Debug
x86
Release
x86
Debug
x64
Release
x64
Debug
ARM
Release
ARM
Debug
ARM64
Release
ARM64
Debug
AnyCPU
Release
AnyCPU
$(MSBuildExtensionsPath)\Microsoft\DesktopBridge\
a662afbb-d12b-4b79-aec8-c85f430add7d
10.0.22000.0
10.0.14393.0
zh-CN
True
$(NoWarn);NU1702
..\PhotoTimeFix\PhotoTimeFix.csproj
False
5907AAB205F7C8B8C6EDE56581A020B40AFE0434
SHA256
False
False
neutral
0
True
e6ae2838-0ea9-4ca4-b878-de86c2133071
Always
en
Always
en
Always
en
Always
en
Always
en
Always
en
Always
en
Always
en
Always
en
Always
en
Designer