You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
photo_sorter/Form1.cs

678 lines
26 KiB

using System;
//using System.Configuration;
//using System.Collections.Generic;
//using System.ComponentModel;
//using System.Data;
using System.Drawing;
//using System.Drawing.Drawing2D;
//using System.Linq;
//using System.Text;
//using System.Threading.Tasks;
using System.Windows.Forms;
using System.Collections;//.ArrayList;
using System.IO;
using ImageMagick;
namespace photo_sorter
{
public partial class form_main : Form
{
public form_main()
{
InitializeComponent();
switch (Properties.Settings.Default.img_format)
{
case "nef":
rad_nef.Checked = true;
break;
case "cr2":
rad_cr2.Checked = true;
break;
case "dng":
rad_dng.Checked = true;
break;
case "jpeg":
rad_jpeg.Checked = true;
break;
case "png":
rad_png.Checked = true;
break;
default:
rad_nef.Checked = true;
break;
}
if (Properties.Settings.Default.global_hotkeys)
tsi_enableGlobalHotkeys.Checked = true;
else
tsi_enableGlobalHotkeys.Checked = false;
if (Properties.Settings.Default.copy_on_sort)
{
rad_sort_copy.Checked = true;
}
else
{
rad_sort_move.Checked = true;
}
tbox_dest_dir.Text = Properties.Settings.Default.dest_dir;
tbox_source_dir.Text = Properties.Settings.Default.src_dir;
if (Directory.Exists(tbox_source_dir.Text))
{
btn_reload_src.Enabled = true;
reload_source();
}
if (Properties.Settings.Default.cbi_primary != null)
{
cbox_sort_primary.Items.AddRange(Properties.Settings.Default.cbi_primary.ToArray());
}
if (Properties.Settings.Default.cbi_secondary != null)
{
cbox_sort_secondary.Items.AddRange(Properties.Settings.Default.cbi_secondary.ToArray());
}
}
static class global
{
public static string dest = Properties.Settings.Default.dest_dir;
public static string src = Properties.Settings.Default.src_dir;
public static string[] filenames;
public static int filecount;
public static int position = 0;
}
public void status_msg(string msg, int lvl = 1)
{
string mtype = "UNDEFINED";
switch (lvl)
{
case 1:
mtype = "INFO";
//stat_last_action.ForeColor = new System.Drawing.Color();
stat_last_action.ForeColor = Color.Black;
break;
case 2:
mtype = "WARN";
stat_last_action.ForeColor = Color.Olive;
break;
case 3:
mtype = "ERROR";
System.Media.SystemSounds.Asterisk.Play();
stat_last_action.ForeColor = Color.Red;
break;
case 4:
mtype = "CRITICAL";
System.Media.SystemSounds.Exclamation.Play();
stat_last_action.ForeColor = Color.Red;
break;
}
stat_last_action.Text = mtype + ": " + msg;
status_bar.Update();
}
private void update_counter()
{
lbl_counter.Text = (global.position + 1).ToString() + " of " + global.filecount.ToString();
}
private void reload_source()
{
global.filenames = populate_file_names();
global.filecount = global.filenames.Length;
global.position = 0;
if (global.filecount > 0)
{
gbox_preview.Enabled = true;
lbl_counter.Text = (global.position + 1).ToString() + " of " + global.filecount.ToString();
update_image();
status_msg("Source directory updated, found " + global.filecount.ToString() + " images");
}
else
{
gbox_preview.Enabled = false;
status_msg("Source directory updated, but no images found!",3);
}
}
private void populate_directory_lists()
{
//string[] pdir = Directory.GetDirectories(global.dest);
//string[] sdir = Directory.GetDirectories(global.dest + "\\" + cbox_sort_primary.Text);
lbox_primary_sortlist.Items.Clear();
foreach (var d in Directory.GetDirectories(global.dest))
{
var dir = new DirectoryInfo(d).Name;
lbox_primary_sortlist.Items.Add(dir);
}
if (cbox_sort_primary.Text.Length > 0)
{
if (Directory.Exists(global.dest + "\\" + cbox_sort_primary.Text))
{
lbox_secondary_sortlist.Items.Clear();
foreach (var d in Directory.GetDirectories(global.dest + "\\" + cbox_sort_primary.Text))
{
var dir = new DirectoryInfo(d).Name;
lbox_secondary_sortlist.Items.Add(dir);
}
}
}
}
private void select_source_dir()
{
if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
{
global.src = folderBrowserDialog1.SelectedPath;
tbox_source_dir.Text = global.src;
status_msg("Opening source directory: " + global.src);
btn_reload_src.Enabled = true;
if (Properties.Settings.Default.src_dir != global.src)
{
Properties.Settings.Default.src_dir = global.src;
Properties.Settings.Default.Save();
}
reload_source();
}
}
private void select_dest_dir()
{
if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
{
global.dest = folderBrowserDialog1.SelectedPath;
tbox_dest_dir.Text = global.dest;
if (Properties.Settings.Default.dest_dir != global.dest)
{
Properties.Settings.Default.dest_dir = global.dest;
Properties.Settings.Default.Save();
}
status_msg("Destination directory updated");
}
}
private void update_image()
{
string fname;
if (global.filecount == 0)
{
fname = "EMPTY - Select new source";
img_preview.Visible = false;
gbox_preview.Enabled = false;
}
else
{
pbar.Value = 6;
pbar.Value -= 1; // This 'hack' forces an instant progress bar update
stat_bar_label.Text = "Getting file info...";
stat_bar_label.Visible = true;
if (global.filecount <= 1)
{
btn_next.Enabled = false;
btn_prev.Enabled = false;
}
else
{
btn_next.Enabled = true;
btn_prev.Enabled = true;
}
status_bar.Refresh();
fname = global.filenames[global.position];
pbar.Value += 5;
stat_bar_label.Text = "Allocating memory...";
status_bar.Refresh();
Image img;
using (MemoryStream img_stream = new MemoryStream())
{
pbar.Value += 10;
lbl_current_fname.Text = "Loading: " + Path.GetFileName(fname);
//img_preview.Image = ToolStripRenderer.CreateDisabledImage(img_preview.Image); //Grey out image (affects performance negatively)
img_preview.Visible = false;
gbox_preview.Enabled = false;
pbar.Value += 10;
stat_bar_label.Text = "Analyzing image...";
status_bar.Refresh();
// Convert RAW file to JPEG in memory
using (var raw_img = new MagickImage(fname))
{
if (raw_img != null)
{
pbar.Value += 50;
raw_img.AutoOrient();
img_stream.Position = 0;
raw_img.Write(img_stream, ImageMagick.MagickFormat.Jpeg);
//raw_img.Write(img_stream, ImageMagick.MagickFormat.Png);
pbar.Value += 15;
stat_bar_label.Text = "Generating preview...";
status_bar.Refresh();
}
}
img_stream.Position = 0;
using (var bmp = new Bitmap(img_stream))
{
img = new Bitmap(bmp);
}
pbar.Value -= 1;
pbar.Value += 6;
//pbar.Value -= 1;
}
img_preview.Image = img;
stat_bar_label.Text = "Done!";
img_preview.Visible = true;
gbox_preview.Enabled = true;
stat_bar_label.Visible = false;
GC.Collect();
GC.WaitForPendingFinalizers();
}
lbl_current_fname.Text = Path.GetFileName(fname);
if (global.filecount > 0)
status_msg("Loaded image: " + lbl_current_fname.Text);
update_counter();
pbar.Value = 0;
populate_directory_lists();
}
public string[] populate_file_names()
{
string ext = "";
if (rad_nef.Checked)
ext = "nef";
if (rad_cr2.Checked)
ext = "cr2";
if (rad_dng.Checked)
ext = "dng";
if (rad_jpeg.Checked)
ext = "jpg";
if (rad_png.Checked)
ext = "png";
string[] files = Directory.GetFiles(global.src, "*." + ext);
if (Properties.Settings.Default.img_format != ext)
{
Properties.Settings.Default.img_format = ext;
Properties.Settings.Default.Save();
}
return files;
}
public void remove_index(int index)
{
for (int i = index; i < global.filenames.Length - 1; i++)
{
global.filenames[i] = global.filenames[i + 1];
}
Array.Resize(ref global.filenames, global.filenames.Length - 1);
global.filecount--;
if (global.position > global.filecount - 1)
{
global.position = global.filecount - 1;
}
}
protected override bool ProcessCmdKey(ref Message msg, Keys key_data)
{
if (tsi_enableGlobalHotkeys.Checked)
{
switch (key_data)
{
case Keys.PageUp:
if (global.filecount > 1)
prev_image();
return true;
case Keys.PageDown:
if (global.filecount > 1)
next_image();
return true;
case Keys.Shift | Keys.Home:
if (global.filecount > 1)
{
status_msg("Loading first image...");
global.position = 0;
update_image();
}
return true;
case Keys.Shift | Keys.End:
if (global.filecount > 1)
{
status_msg("Loading final image...");
global.position = global.filecount - 1;
update_image();
}
return true;
case Keys.Enter:
sort_image();
return true;
case Keys.Delete:
delete_image();
return true;
case Keys.Shift | Keys.Enter:
delete_image();
return true;
}
}
return base.ProcessCmdKey(ref msg, key_data);
}
public void next_image()
{
status_msg("Loading next image...");
if (global.position < global.filecount - 1)
{
global.position += 1;
}
else
{
global.position = 0;
}
update_image();
}
public void prev_image()
{
status_msg("Loading previous image...");
if (global.position > 0)
{
global.position -= 1;
}
else
{
global.position = global.filecount - 1;
}
update_image();
}
public void sort_image()
{
string prim_dir = global.dest + '\\' + cbox_sort_primary.Text;
string sec_dir = prim_dir + '\\' + cbox_sort_secondary.Text;
string dpath;
if (global.dest == "")
{
status_msg("Destination directory must be set first!", 3);
//System.Media.SystemSounds.Exclamation.Play();
//MessageBox.Show("Destination directory must be set\nbefore images can be sorted!", "Error: Primary Sort", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (cbox_sort_primary.Text == "")
{
status_msg("Primary sort field required to sort!", 3);
//System.Media.SystemSounds.Exclamation.Play();
//MessageBox.Show("Primary sort directory name is required!", "Error: Primary Sort", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
if (cbox_sort_secondary.Text == "")
{
dpath = prim_dir;
}
else
{
dpath = sec_dir;
if (!Directory.Exists(sec_dir))
{
Directory.CreateDirectory(sec_dir);
status_msg("Created directory '" + sec_dir + "'", 2);
}
}
if (!Directory.Exists(prim_dir))
{
Directory.CreateDirectory(prim_dir);
status_msg("Created directory '" + prim_dir + "'", 2);
}
string src_fname = global.filenames[global.position];
string dst_fname = dpath + "\\" + Path.GetFileName(global.filenames[global.position]);
if (rad_sort_move.Checked)
{
try
{
if (File.Exists(@dst_fname))
{
if (MessageBox.Show("This file already exists in the destination directory. Would you like to overwrite it?", "Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
File.Delete(dst_fname);
status_msg("Deleted " + dst_fname, 2);
}
else
{
status_msg("Move aborted for " + src_fname, 2);
}
}
File.Move(@src_fname, @dst_fname);
status_msg("Moved " + global.filenames[global.position] + " to " + dpath);
remove_index(global.position);
update_image();
}
catch (IOException ex)
{
status_msg("Unable to move " + global.filenames[global.position] + " to " + dpath + "!", 4);
MessageBox.Show(ex.ToString(), "Critical: IO Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
if (Properties.Settings.Default.copy_on_sort)
{
Properties.Settings.Default.copy_on_sort = false;
Properties.Settings.Default.Save();
}
}
else
{
try
{
if (File.Exists(@dst_fname))
{
if (MessageBox.Show("This file already exists in the destination directory. Would you like to overwrite it?", "Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
File.Delete(dst_fname);
status_msg("Deleted " + dst_fname, 2);
}
else
{
status_msg("Copy aborted for " + src_fname, 2);
return;
}
}
File.Copy(@src_fname, @dst_fname);
//status_msg("Copied " + lbl_current_fname.Text + " to " + dpath);
status_msg("Copied " + global.filenames[global.position] + " to " + dpath);
remove_index(global.position);
update_image();
}
catch (IOException ex)
{
status_msg("Unable to copy " + global.filenames[global.position] + " to " + dpath + "!", 4);
MessageBox.Show(ex.ToString(), "Critical: IO Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
// Begin Update comboboxes
if (cbox_sort_primary.Items.Contains(cbox_sort_primary.Text))
{
//Remove and re-add, to put it at the new end of the list
cbox_sort_primary.Items.Remove(cbox_sort_primary.Text);
cbox_sort_primary.Items.Add(cbox_sort_primary.Text);
}
else
{
cbox_sort_primary.Items.Add(cbox_sort_primary.Text);
}
if (cbox_sort_secondary.Text.Length > 0)
{
if (cbox_sort_secondary.Items.Contains(cbox_sort_secondary.Text))
{
//Remove and re-add, to put it at the new end of the list
cbox_sort_secondary.Items.Remove(cbox_sort_secondary.Text);
cbox_sort_secondary.Items.Add(cbox_sort_secondary.Text);
}
else
{
cbox_sort_secondary.Items.Add(cbox_sort_secondary.Text);
}
}
// End combobox updating
if (!Properties.Settings.Default.copy_on_sort)
{
Properties.Settings.Default.copy_on_sort = true;
Properties.Settings.Default.Save();
}
}
}
public void delete_image()
{
if (MessageBox.Show("Are you sure you want to delete this photo?", "Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
string src_fname = global.filenames[global.position];
try
{
File.Delete(src_fname);
status_msg("Deleted file: " + src_fname, 2);
remove_index(global.position);
update_image();
}
catch (IOException ex)
{
status_msg("Unable to delete " + src_fname + "!", 4);
MessageBox.Show(ex.ToString(), "Critical: IO Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
public void prerender_init()
{
if (MessageBox.Show("WARNING: Pre-rendering your photos may take a long time, and the preview image quality will be lower than normal.\n\nWould you like to proceed?", "Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
MessageBox.Show("Pre-rendering would normally have started, but instead, nothing interesting happens.");
}
else
{
MessageBox.Show("You've chickened out and abandoned the pre-render process. Nothing interesting happens.");
}
}
//
// UI Interactions
//
///////////////////////////////////////////////////////
private void btn_open_dir_Click(object sender, EventArgs e)
{
select_dest_dir();
}
private void openDirectoryToolStripMenuItem_Click(object sender, EventArgs e)
{
select_source_dir();
}
private void selectDestinationDirectoryToolStripMenuItem_Click(object sender, EventArgs e)
{
select_dest_dir();
}
private void quitApplicationToolStripMenuItem_Click(object sender, EventArgs e)
{
if (MessageBox.Show("Are you sure you want to quit the Photo Sorter application?", "Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
this.Close();
}
}
private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
{
MessageBox.Show("Photo Sorter v1.0.2\n\nThis application is Copyright \u00A9 Aaron Johnson, 2023.\n\nPlease visit https://www.skyfall.tech/ for more information.");
}
private void btn_open_src_dir_Click(object sender, EventArgs e)
{
select_source_dir();
}
private void btn_prev_Click(object sender, EventArgs e)
{
prev_image();
}
private void btn_next_Click(object sender, EventArgs e)
{
next_image();
}
private void btn_sort_Click(object sender, EventArgs e)
{
sort_image();
}
private void btn_reload_src_Click(object sender, EventArgs e)
{
reload_source();
}
private void globalHotkeysListToolStripMenuItem_Click(object sender, EventArgs e)
{
MessageBox .Show("Global Hotkeys\n\nPgUp == Previous image\nPgDn == Next image\nHome == Go to first unsorted image\nEnd == Go to final unsorted image\n\nEnter == Sort photo to current options\n");
}
private void tsi_enableGlobalHotkeys_Click(object sender, EventArgs e)
{
if (tsi_enableGlobalHotkeys.Checked)
Properties.Settings.Default.global_hotkeys = true;
else
Properties.Settings.Default.global_hotkeys = false;
Properties.Settings.Default.Save();
}
private void btn_delete_Click(object sender, EventArgs e)
{
delete_image();
}
private void btn_prerender_Click(object sender, EventArgs e)
{
prerender_init();
}
private void cbox_sortfields_Leave(object sender, EventArgs e)
{
populate_directory_lists();
}
private void cbox_sort_primary_Enter(object sender, EventArgs e)
{
populate_directory_lists();
tabctrl_sort_dir.SelectedTab = tabctrl_sort_dir.TabPages["tab_primesort"];
cbox_sort_primary.Focus();
}
private void cbox_sort_secondary_Enter(object sender, EventArgs e)
{
if (cbox_sort_primary.Text.Length > 0)
{
populate_directory_lists();
tabctrl_sort_dir.SelectedTab = tabctrl_sort_dir.TabPages["tab_secondsort"];
cbox_sort_secondary.Focus();
}
}
private void lbox_primary_sortlist_SelectItem(object sender, EventArgs e)
{
cbox_sort_primary.Text = lbox_primary_sortlist.SelectedItem.ToString();
populate_directory_lists();
}
private void lbox_secondary_sortlist_SelectItem(object sender, EventArgs e)
{
cbox_sort_secondary.Text = lbox_secondary_sortlist.SelectedItem.ToString();
}
private void Form1_FormClosing(Object sender, FormClosingEventArgs e)
{
if (MessageBox.Show("Are you sure you want to quit the Photo Sorter application?", "Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
ArrayList cbi_primary = new ArrayList(this.cbox_sort_primary.Items);
ArrayList cbi_secondary = new ArrayList(this.cbox_sort_secondary.Items);
Properties.Settings.Default.cbi_primary = cbi_primary;
Properties.Settings.Default.cbi_secondary = cbi_secondary;
Properties.Settings.Default.Save();
}
else
{
e.Cancel = true;
}
}
}
}