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.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; } 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(); } } 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 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; } 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 keyData) { if (tsi_enableGlobalHotkeys.Checked) { if (keyData == Keys.Enter) { sort_image(); return true; } if (keyData == Keys.PageUp) { if (global.filecount > 1) prev_image(); return true; } if (keyData == Keys.PageDown) { if (global.filecount > 1) next_image(); return true; } if (keyData == Keys.Home) { if (global.filecount > 1) { status_msg("Loading first image..."); global.position = 0; update_image(); } return true; } if (keyData == Keys.End) { if (global.filecount > 1) { status_msg("Loading final image..."); global.position = global.filecount - 1; update_image(); } return true; } } return base.ProcessCmdKey(ref msg, keyData); } 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 + '\\' + tbox_sort_primary.Text; string sec_dir = prim_dir + '\\' + tbox_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 (tbox_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 (tbox_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 " + lbl_current_fname.Text + " to " + dpath); 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); } if (!Properties.Settings.Default.copy_on_sort) { Properties.Settings.Default.copy_on_sort = true; Properties.Settings.Default.Save(); } } } // // 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.1\n\nThis application is Copyright \u00A9 Skyfall Tech, 2022-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 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) { this.Close(); } else { e.Cancel = true; } }*/ } }