diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cf445f2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +### + +[Oo]bj/ +[Bb]in/ + +.vs +*.suo +*.user \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bff494c --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6e4094c --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +Digital cameras and mobile phones create image file formats such as JPEG. These files contains hidden data or metadata called EXIF (Exchangeable image file format) which can include the date, time and sometimes the GPS coordinates of the picture, the brand and serial number of the device which took it as well as a thumbnail of the original image. Metanull can remove the metadata from your image files so the image you have won't have kind of information that identify you in it. + +To avoid these kind of issues you can remove metadata selectively, that is by removing sensitive information but keeping other useful information in the images. This can be achieved in Windows, right clicking on and selecting properties, details tab, you can remove metadata from here. But if you have large number of photos that you want to remove Exif or metadata Windows Explorer is not the convenient way to do that. + +Metanull is a portable Windows application that can remove metadata from your photos or images. It can be used to remove exif data from single or multiple images. The program is simple to use, select a single image or select a folder to batch remove meta information. Then select where you want to store meta data stripped images. Once done just hit the Null It button. + +It will do the job in a min or so depending on the number of images you through at it. See the below image showing before and after stripping exif data with the program. \ No newline at end of file diff --git a/src/Metanull.sln b/src/Metanull.sln new file mode 100644 index 0000000..270fa0b --- /dev/null +++ b/src/Metanull.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Metanull", "Metanull\Metanull.csproj", "{DEEC1279-0CF6-4BD2-A903-2ADE9DA9E7A1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DEEC1279-0CF6-4BD2-A903-2ADE9DA9E7A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DEEC1279-0CF6-4BD2-A903-2ADE9DA9E7A1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DEEC1279-0CF6-4BD2-A903-2ADE9DA9E7A1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DEEC1279-0CF6-4BD2-A903-2ADE9DA9E7A1}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/Metanull/MainForm.Designer.cs b/src/Metanull/MainForm.Designer.cs new file mode 100644 index 0000000..bb4c277 --- /dev/null +++ b/src/Metanull/MainForm.Designer.cs @@ -0,0 +1,352 @@ +namespace Metanull +{ + partial class MainForm + { + /// + /// Требуется переменная конструктора. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Освободить все используемые ресурсы. + /// + /// истинно, если управляемый ресурс должен быть удален; иначе ложно. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Код, автоматически созданный конструктором форм Windows + + /// + /// Обязательный метод для поддержки конструктора - не изменяйте + /// содержимое данного метода при помощи редактора кода. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.label2 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.nullItButton = new System.Windows.Forms.Button(); + this.progressBar = new System.Windows.Forms.ProgressBar(); + this.openFileDialog = new System.Windows.Forms.OpenFileDialog(); + this.sourceFolderDialog = new System.Windows.Forms.FolderBrowserDialog(); + this.destFolderDialog = new System.Windows.Forms.FolderBrowserDialog(); + this.logTextBox = new System.Windows.Forms.TextBox(); + this.stopButton = new System.Windows.Forms.Button(); + this.waitTimer = new System.Windows.Forms.Timer(this.components); + this.sourceFolderTreeCheckBox = new System.Windows.Forms.CheckBox(); + this.destFolderButton = new System.Windows.Forms.Button(); + this.destFolderTextBox = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.recursiveCheckBox = new System.Windows.Forms.CheckBox(); + this.batchFolderBrowseButton = new System.Windows.Forms.Button(); + this.singleFileSelectButton = new System.Windows.Forms.Button(); + this.batchFolderTextBox = new System.Windows.Forms.TextBox(); + this.batchFolderRadio = new System.Windows.Forms.RadioButton(); + this.singleFileRadio = new System.Windows.Forms.RadioButton(); + this.singleFileTextBox = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.BackColor = System.Drawing.SystemColors.ControlDark; + this.label2.Font = new System.Drawing.Font("Tahoma", 24F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204))); + this.label2.ForeColor = System.Drawing.SystemColors.ControlLightLight; + this.label2.Location = new System.Drawing.Point(12, 13); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(34, 39); + this.label2.TabIndex = 5; + this.label2.Text = "1"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.BackColor = System.Drawing.SystemColors.ControlDark; + this.label3.Font = new System.Drawing.Font("Tahoma", 24F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204))); + this.label3.ForeColor = System.Drawing.SystemColors.ControlLightLight; + this.label3.Location = new System.Drawing.Point(12, 117); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(34, 39); + this.label3.TabIndex = 6; + this.label3.Text = "2"; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.BackColor = System.Drawing.SystemColors.ControlDark; + this.label5.Font = new System.Drawing.Font("Tahoma", 24F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(204))); + this.label5.ForeColor = System.Drawing.SystemColors.ControlLightLight; + this.label5.Location = new System.Drawing.Point(12, 194); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(34, 39); + this.label5.TabIndex = 11; + this.label5.Text = "3"; + // + // nullItButton + // + this.nullItButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.nullItButton.Font = new System.Drawing.Font("Tahoma", 8F, System.Drawing.FontStyle.Bold); + this.nullItButton.ForeColor = System.Drawing.Color.Black; + this.nullItButton.Location = new System.Drawing.Point(405, 194); + this.nullItButton.Name = "nullItButton"; + this.nullItButton.Size = new System.Drawing.Size(75, 23); + this.nullItButton.TabIndex = 14; + this.nullItButton.Text = "Null It!"; + this.nullItButton.UseVisualStyleBackColor = true; + this.nullItButton.Click += new System.EventHandler(this.nullItButton_Click); + // + // progressBar + // + this.progressBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.progressBar.Location = new System.Drawing.Point(55, 194); + this.progressBar.Name = "progressBar"; + this.progressBar.Size = new System.Drawing.Size(263, 23); + this.progressBar.Style = System.Windows.Forms.ProgressBarStyle.Continuous; + this.progressBar.TabIndex = 16; + // + // openFileDialog + // + this.openFileDialog.Filter = "JPG, JPEG (*.jpg, *.jpeg)|*.jp*g"; + // + // logTextBox + // + this.logTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.logTextBox.BackColor = System.Drawing.Color.Black; + this.logTextBox.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(128)))), ((int)(((byte)(0))))); + this.logTextBox.Location = new System.Drawing.Point(55, 223); + this.logTextBox.Multiline = true; + this.logTextBox.Name = "logTextBox"; + this.logTextBox.ReadOnly = true; + this.logTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.logTextBox.Size = new System.Drawing.Size(425, 95); + this.logTextBox.TabIndex = 17; + // + // stopButton + // + this.stopButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.stopButton.Enabled = false; + this.stopButton.Location = new System.Drawing.Point(324, 194); + this.stopButton.Name = "stopButton"; + this.stopButton.Size = new System.Drawing.Size(75, 23); + this.stopButton.TabIndex = 18; + this.stopButton.Text = "Stop"; + this.stopButton.UseVisualStyleBackColor = true; + this.stopButton.Click += new System.EventHandler(this.stopButton_Click); + // + // waitTimer + // + this.waitTimer.Interval = 300; + this.waitTimer.Tick += new System.EventHandler(this.waitTimer_Tick); + // + // sourceFolderTreeCheckBox + // + this.sourceFolderTreeCheckBox.AutoSize = true; + this.sourceFolderTreeCheckBox.Checked = true; + this.sourceFolderTreeCheckBox.CheckState = System.Windows.Forms.CheckState.Checked; + this.sourceFolderTreeCheckBox.Location = new System.Drawing.Point(151, 162); + this.sourceFolderTreeCheckBox.Name = "sourceFolderTreeCheckBox"; + this.sourceFolderTreeCheckBox.Size = new System.Drawing.Size(159, 17); + this.sourceFolderTreeCheckBox.TabIndex = 26; + this.sourceFolderTreeCheckBox.Text = "Recreate source folder tree"; + this.sourceFolderTreeCheckBox.UseVisualStyleBackColor = true; + // + // destFolderButton + // + this.destFolderButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.destFolderButton.Location = new System.Drawing.Point(405, 134); + this.destFolderButton.Name = "destFolderButton"; + this.destFolderButton.Size = new System.Drawing.Size(75, 23); + this.destFolderButton.TabIndex = 25; + this.destFolderButton.Text = "Browse..."; + this.destFolderButton.UseVisualStyleBackColor = true; + this.destFolderButton.Click += new System.EventHandler(this.destFolderButton_Click); + // + // destFolderTextBox + // + this.destFolderTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.destFolderTextBox.BackColor = System.Drawing.SystemColors.Window; + this.destFolderTextBox.Location = new System.Drawing.Point(151, 136); + this.destFolderTextBox.Name = "destFolderTextBox"; + this.destFolderTextBox.ReadOnly = true; + this.destFolderTextBox.Size = new System.Drawing.Size(248, 20); + this.destFolderTextBox.TabIndex = 24; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Tahoma", 8F, System.Drawing.FontStyle.Bold); + this.label1.ForeColor = System.Drawing.SystemColors.ControlDarkDark; + this.label1.Location = new System.Drawing.Point(52, 117); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(140, 13); + this.label1.TabIndex = 27; + this.label1.Text = "Copy result image(s) to"; + // + // recursiveCheckBox + // + this.recursiveCheckBox.AutoSize = true; + this.recursiveCheckBox.Checked = true; + this.recursiveCheckBox.CheckState = System.Windows.Forms.CheckState.Checked; + this.recursiveCheckBox.Location = new System.Drawing.Point(151, 86); + this.recursiveCheckBox.Name = "recursiveCheckBox"; + this.recursiveCheckBox.Size = new System.Drawing.Size(124, 17); + this.recursiveCheckBox.TabIndex = 34; + this.recursiveCheckBox.Text = "Also scan subfolders"; + this.recursiveCheckBox.UseVisualStyleBackColor = true; + this.recursiveCheckBox.CheckedChanged += new System.EventHandler(this.recursiveCheckBox_CheckedChanged); + // + // batchFolderBrowseButton + // + this.batchFolderBrowseButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.batchFolderBrowseButton.Location = new System.Drawing.Point(405, 58); + this.batchFolderBrowseButton.Name = "batchFolderBrowseButton"; + this.batchFolderBrowseButton.Size = new System.Drawing.Size(75, 23); + this.batchFolderBrowseButton.TabIndex = 33; + this.batchFolderBrowseButton.Text = "Browse..."; + this.batchFolderBrowseButton.UseVisualStyleBackColor = true; + this.batchFolderBrowseButton.Click += new System.EventHandler(this.batchFolderBrowseButton_Click); + // + // singleFileSelectButton + // + this.singleFileSelectButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.singleFileSelectButton.Location = new System.Drawing.Point(405, 29); + this.singleFileSelectButton.Name = "singleFileSelectButton"; + this.singleFileSelectButton.Size = new System.Drawing.Size(75, 23); + this.singleFileSelectButton.TabIndex = 32; + this.singleFileSelectButton.Text = "Select..."; + this.singleFileSelectButton.UseVisualStyleBackColor = true; + this.singleFileSelectButton.Click += new System.EventHandler(this.singleFileSelectButton_Click); + // + // batchFolderTextBox + // + this.batchFolderTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.batchFolderTextBox.BackColor = System.Drawing.SystemColors.Window; + this.batchFolderTextBox.Location = new System.Drawing.Point(151, 60); + this.batchFolderTextBox.Name = "batchFolderTextBox"; + this.batchFolderTextBox.ReadOnly = true; + this.batchFolderTextBox.Size = new System.Drawing.Size(248, 20); + this.batchFolderTextBox.TabIndex = 31; + this.batchFolderTextBox.TextChanged += new System.EventHandler(this.batchFolderTextBox_TextChanged); + // + // batchFolderRadio + // + this.batchFolderRadio.AutoSize = true; + this.batchFolderRadio.Location = new System.Drawing.Point(58, 61); + this.batchFolderRadio.Name = "batchFolderRadio"; + this.batchFolderRadio.Size = new System.Drawing.Size(87, 17); + this.batchFolderRadio.TabIndex = 30; + this.batchFolderRadio.TabStop = true; + this.batchFolderRadio.Text = "Batch folder:"; + this.batchFolderRadio.UseVisualStyleBackColor = true; + // + // singleFileRadio + // + this.singleFileRadio.AutoSize = true; + this.singleFileRadio.Location = new System.Drawing.Point(58, 35); + this.singleFileRadio.Name = "singleFileRadio"; + this.singleFileRadio.Size = new System.Drawing.Size(74, 17); + this.singleFileRadio.TabIndex = 29; + this.singleFileRadio.TabStop = true; + this.singleFileRadio.Text = "Single file:"; + this.singleFileRadio.UseVisualStyleBackColor = true; + this.singleFileRadio.CheckedChanged += new System.EventHandler(this.singleFileRadio_CheckedChanged); + // + // singleFileTextBox + // + this.singleFileTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.singleFileTextBox.BackColor = System.Drawing.SystemColors.Window; + this.singleFileTextBox.Location = new System.Drawing.Point(151, 32); + this.singleFileTextBox.Name = "singleFileTextBox"; + this.singleFileTextBox.ReadOnly = true; + this.singleFileTextBox.Size = new System.Drawing.Size(248, 20); + this.singleFileTextBox.TabIndex = 28; + this.singleFileTextBox.TextChanged += new System.EventHandler(this.singleFileTextBox_TextChanged); + // + // label4 + // + this.label4.AutoSize = true; + this.label4.BackColor = System.Drawing.SystemColors.Control; + this.label4.Font = new System.Drawing.Font("Tahoma", 8F, System.Drawing.FontStyle.Bold); + this.label4.ForeColor = System.Drawing.SystemColors.ControlDarkDark; + this.label4.Location = new System.Drawing.Point(52, 13); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(100, 13); + this.label4.TabIndex = 35; + this.label4.Text = "Source image(s)"; + // + // MainForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(492, 330); + this.Controls.Add(this.label4); + this.Controls.Add(this.recursiveCheckBox); + this.Controls.Add(this.batchFolderBrowseButton); + this.Controls.Add(this.singleFileSelectButton); + this.Controls.Add(this.batchFolderTextBox); + this.Controls.Add(this.batchFolderRadio); + this.Controls.Add(this.singleFileRadio); + this.Controls.Add(this.singleFileTextBox); + this.Controls.Add(this.label1); + this.Controls.Add(this.sourceFolderTreeCheckBox); + this.Controls.Add(this.destFolderButton); + this.Controls.Add(this.destFolderTextBox); + this.Controls.Add(this.stopButton); + this.Controls.Add(this.logTextBox); + this.Controls.Add(this.progressBar); + this.Controls.Add(this.nullItButton); + this.Controls.Add(this.label5); + this.Controls.Add(this.label3); + this.Controls.Add(this.label2); + this.MinimumSize = new System.Drawing.Size(427, 339); + this.Name = "MainForm"; + this.Text = "Metanull"; + this.Load += new System.EventHandler(this.MainForm_Load); + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_FormClosing); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Button nullItButton; + private System.Windows.Forms.ProgressBar progressBar; + private System.Windows.Forms.OpenFileDialog openFileDialog; + private System.Windows.Forms.FolderBrowserDialog sourceFolderDialog; + private System.Windows.Forms.FolderBrowserDialog destFolderDialog; + private System.Windows.Forms.TextBox logTextBox; + private System.Windows.Forms.Button stopButton; + private System.Windows.Forms.Timer waitTimer; + private System.Windows.Forms.CheckBox sourceFolderTreeCheckBox; + private System.Windows.Forms.Button destFolderButton; + private System.Windows.Forms.TextBox destFolderTextBox; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.CheckBox recursiveCheckBox; + private System.Windows.Forms.Button batchFolderBrowseButton; + private System.Windows.Forms.Button singleFileSelectButton; + private System.Windows.Forms.TextBox batchFolderTextBox; + private System.Windows.Forms.RadioButton batchFolderRadio; + private System.Windows.Forms.RadioButton singleFileRadio; + private System.Windows.Forms.TextBox singleFileTextBox; + private System.Windows.Forms.Label label4; + } +} + diff --git a/src/Metanull/MainForm.cs b/src/Metanull/MainForm.cs new file mode 100644 index 0000000..6f40042 --- /dev/null +++ b/src/Metanull/MainForm.cs @@ -0,0 +1,358 @@ +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using System.Reflection; +using System.Threading; +using System.IO; + +namespace Metanull +{ + public partial class MainForm : Form + { + string log = string.Empty; + bool isRun = false; + List images = new List(); + + public MainForm() + { + InitializeComponent(); + //recreate the folder tree + } + + private void singleFileSelectButton_Click(object sender, EventArgs e) + { + if (openFileDialog.ShowDialog() == DialogResult.OK) + { + singleFileRadio.Select(); + singleFileTextBox.Text = openFileDialog.FileName; + } + } + + private void batchFolderBrowseButton_Click(object sender, EventArgs e) + { + if (sourceFolderDialog.ShowDialog() == DialogResult.OK) + { + batchFolderRadio.Select(); + batchFolderTextBox.Text = sourceFolderDialog.SelectedPath; + } + } + + private void destFolderButton_Click(object sender, EventArgs e) + { + if (destFolderDialog.ShowDialog() == DialogResult.OK) + { + destFolderTextBox.Text = destFolderDialog.SelectedPath; + } + } + + private void LogLn(string text) + { + Log(text + Environment.NewLine); + } + + private void Log(string text) + { + log += text; + try + { + if (logTextBox == null) return; + logTextBox.BeginInvoke( + new MethodInvoker( + delegate { + logTextBox.Text = log; + logTextBox.SelectionStart = logTextBox.Text.Length; + logTextBox.ScrollToCaret(); + })); + } + catch { } + } + + private void UpdateProgress(int progress) + { + try + { + if (progressBar == null) return; + progressBar.BeginInvoke( + new MethodInvoker( + delegate + { + progressBar.Value = progress; + })); + } + catch { } + } + + private void MainForm_Load(object sender, EventArgs e) + { + this.Text = "Metanull 1.1"; + LogLn("Metanull version " + Assembly.GetExecutingAssembly().GetName().Version.ToString()); + Log(@"Copyright © 2012-2013 Nikolai Voronin + +https://github.com/nikvoronin/Metanull + +"); + } + + private void nullItButton_Click(object sender, EventArgs e) + { + images.Clear(); + if (batchFolderRadio.Checked) + { + SearchOption opts = + recursiveCheckBox.Checked ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; + string[] files = Directory.GetFiles(batchFolderTextBox.Text, "*.jp*g", opts); + images.AddRange(files); + } + else + { + images.Add(singleFileTextBox.Text); + } + + stopButton.Enabled = true; + nullItButton.Enabled = false; + singleFileRadio.Enabled = false; + singleFileTextBox.Enabled = false; + singleFileSelectButton.Enabled = false; + batchFolderBrowseButton.Enabled = false; + batchFolderRadio.Enabled = false; + batchFolderTextBox.Enabled = false; + destFolderTextBox.Enabled = false; + destFolderButton.Enabled = false; + recursiveCheckBox.Enabled = false; + sourceFolderTreeCheckBox.Enabled = false; + + progressBar.Value = 0; + isRun = true; + waitTimer.Enabled = true; + + Thread thread = new Thread( + (ThreadStart)delegate + { + NullIt(batchFolderTextBox.Text); + }); + thread.Priority = ThreadPriority.BelowNormal; + thread.Start(); + } + + private void NullIt(string srcFolder) + { + LogLn("----------------"); + LogLn(""); + DateTime startTime = DateTime.Now; + int alreadyDo = 0; + long totalLenRemoved = 0; + int doFiles = 0; + foreach (string filename in images) + { + BinaryReader reader = + new BinaryReader( + File.Open(filename, FileMode.Open)); + LogLn(filename); + + FileInfo srcFileInfo = new FileInfo(filename); + string comma = filename.Contains("/") ? "/" : "\\"; + string destFolder = destFolderDialog.SelectedPath; + + // Scan source folder tree + if (sourceFolderTreeCheckBox.Checked && + recursiveCheckBox.Checked && + batchFolderRadio.Checked) + { + if (srcFolder != srcFileInfo.DirectoryName) + { + string newSubFolder = + srcFileInfo.DirectoryName.Substring( + srcFolder.Length, + srcFileInfo.DirectoryName.Length - srcFolder.Length); + destFolder += newSubFolder; + Directory.CreateDirectory(destFolder); + } + } + + BinaryWriter writer = + new BinaryWriter( + File.Open(destFolder + comma + srcFileInfo.Name, FileMode.Create)); + + int removedSects = TruncateAll(reader, writer); + LogLn( + "Done: " + + reader.BaseStream.Length + " bytes --> " + + writer.BaseStream.Length + " bytes. " + Environment.NewLine + + "Removed " + formatBytes(reader.BaseStream.Length - writer.BaseStream.Length) + " in " + + removedSects + " sections" + + Environment.NewLine); + + if (removedSects > 0) + { + doFiles++; + totalLenRemoved += reader.BaseStream.Length - writer.BaseStream.Length; + } + + reader.Close(); + writer.Flush(); + writer.Close(); + + alreadyDo++; + UpdateProgress(alreadyDo * 100 / images.Count); + if (!isRun) break; + } + isRun = false; + + DateTime endTime = DateTime.Now; + LogLn( + "Completed (" + + TimeSpan.FromTicks(endTime.Ticks - startTime.Ticks).ToString() + "): removed " + + formatBytes(totalLenRemoved) + " in " + + doFiles + " images." + Environment.NewLine + ); + } + + private string formatBytes(float bytes) + { + string[] Suffix = { "bytes", "KB", "MB", "GB", "TB" }; + int i = 0; + double dblSByte = 0; + if ((int)(bytes / 1024) == 0) + { + return string.Format("{0} bytes", bytes); + } + else + { + for (i = 0; (int)(bytes / 1024) > 0; i++, bytes /= 1024) + { + dblSByte = bytes / 1024.0; + } + return string.Format("{0:0.00} {1}", dblSByte, Suffix[i]); + } + } + + private int TruncateAll(BinaryReader reader, BinaryWriter writer) + { + int sectsRemoved = 0; + long rLen = reader.BaseStream.Length; + long wPos = 2; + byte b1 = reader.ReadByte(); + byte b2 = reader.ReadByte(); + if (b1 != 0xff || b2 != 0xd8) + { + return 0; + } + else + { + writer.Write(b1); + writer.Write(b2); + } + + byte[] buffer; + while (wPos < rLen) + { + // read section marker + buffer = reader.ReadBytes(2); + wPos += 2; + // check end of image marker + if (buffer[0] == 0xff && buffer[1] == 0xd9) + { + writer.Write(buffer); + break; + } + + if (buffer[0] == 0xff && buffer[1] == 0xda) + { + // write section marker + writer.Write(buffer); + byte[] buf = new byte[4096]; + while (wPos < rLen) + { + int readedBytes = reader.Read(buf, 0, buf.Length); + wPos += readedBytes; + writer.Write(buf, 0, readedBytes); + } + } + else + { + if (buffer[0] == 0xff && (buffer[1] < 0xe0 || buffer[1] > 0xee)) + { + // write section marker + writer.Write(buffer); + // read section length + buffer = reader.ReadBytes(2); + wPos += 2; + // write section length + writer.Write(buffer); + int sectionLen = buffer[0] * 256 + buffer[1]; + // read section data + byte[] sectionBuffer = reader.ReadBytes(sectionLen - 2); + wPos += sectionLen - 2; + // write secion buffer + writer.Write(sectionBuffer); + } + else + { + // read section length + buffer = reader.ReadBytes(2); + wPos += 2; + int sectionLen = buffer[0] * 256 + buffer[1]; + // read section data + byte[] sectionBuffer = reader.ReadBytes(sectionLen - 2); + wPos += sectionLen - 2; + sectsRemoved++; + } + } + } + + return sectsRemoved; + } + + private void stopButton_Click(object sender, EventArgs e) + { + waitTimer.Enabled = false; + isRun = false; + + stopButton.Enabled = false; + nullItButton.Enabled = true; + singleFileRadio.Enabled = true; + singleFileTextBox.Enabled = true; + singleFileSelectButton.Enabled = true; + batchFolderBrowseButton.Enabled = true; + batchFolderRadio.Enabled = true; + batchFolderTextBox.Enabled = true; + destFolderTextBox.Enabled = true; + destFolderButton.Enabled = true; + recursiveCheckBox.Enabled = true; + sourceFolderTreeCheckBox.Enabled = true; + } + + private void MainForm_FormClosing(object sender, FormClosingEventArgs e) + { + isRun = false; + } + + private void batchFolderTextBox_TextChanged(object sender, EventArgs e) + { + if (batchFolderTextBox.Text.Trim().Length > 3) + batchFolderRadio.Checked = true; + } + + private void singleFileTextBox_TextChanged(object sender, EventArgs e) + { + if (singleFileTextBox.Text.Trim().Length > 3) + singleFileRadio.Checked = true; + } + + private void waitTimer_Tick(object sender, EventArgs e) + { + if (!isRun) + stopButton_Click(this, e); + } + + private void singleFileRadio_CheckedChanged(object sender, EventArgs e) + { + sourceFolderTreeCheckBox.Enabled = !singleFileRadio.Checked && recursiveCheckBox.Checked; + } + + private void recursiveCheckBox_CheckedChanged(object sender, EventArgs e) + { + sourceFolderTreeCheckBox.Enabled = !singleFileRadio.Checked && recursiveCheckBox.Checked; + } + } +} diff --git a/src/Metanull/MainForm.resx b/src/Metanull/MainForm.resx new file mode 100644 index 0000000..307bd06 --- /dev/null +++ b/src/Metanull/MainForm.resx @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 141, 17 + + + 287, 17 + + + 421, 17 + + \ No newline at end of file diff --git a/src/Metanull/Metanull.csproj b/src/Metanull/Metanull.csproj new file mode 100644 index 0000000..5c893e1 --- /dev/null +++ b/src/Metanull/Metanull.csproj @@ -0,0 +1,88 @@ + + + + Debug + AnyCPU + 9.0.21022 + 2.0 + {DEEC1279-0CF6-4BD2-A903-2ADE9DA9E7A1} + WinExe + Properties + Metanull + Metanull + v2.0 + 512 + + + + + 3.5 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + full + false + ..\..\bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + none + true + ..\..\bin\Release\ + + + prompt + 4 + + + + + + + + + Form + + + MainForm.cs + + + + + MainForm.cs + Designer + + + + + False + .NET Framework 3.5 SP1 + true + + + + + \ No newline at end of file diff --git a/src/Metanull/Program.cs b/src/Metanull/Program.cs new file mode 100644 index 0000000..0ccd6a6 --- /dev/null +++ b/src/Metanull/Program.cs @@ -0,0 +1,16 @@ +using System; +using System.Windows.Forms; + +namespace Metanull +{ + static class Program + { + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new MainForm()); + } + } +} diff --git a/src/Metanull/Properties/AssemblyInfo.cs b/src/Metanull/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..a06b541 --- /dev/null +++ b/src/Metanull/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Reflection; +[assembly: AssemblyTitle("Metanull")] +[assembly: AssemblyDescription("A Windows application for removing metadata from JPEG files which are created by digital cameras or mobile phones.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Nikolai Voronin")] +[assembly: AssemblyProduct("Metanull")] +[assembly: AssemblyCopyright("Copyright © 2012-2013 Nikolai Voronin")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] +[assembly: AssemblyVersion("1.1.*")]