Stwórzmy czym prędzej nowy projekt programu ImageResize, który będzie służył do generowania miniatur zdjęć znajdujących się w podanej lokalizacji i zapisywanie ich do specjalnie utworzonego folderu o nazwie sm_img. Na poniższym rysunku pokazany został widok okna programu.
Ustawienie właściwości okna głównego (nr. 1 na rysunku 1):
(Name) - ImCreator;
Text - ImCreator;
MinimumSize - 799; 265;
MaximumSize - 799; 265;
Size - 799; 265.
Kontrolka TextBox (nr. 2 na rysunku 1):
(Name) - tb_path;
Location - 7; 35;
Size - 746; 20
Kontrolka Button (nr. 3 na rysunku 1):
(Name) - bt_browse;
Location - 754; 35;
Size - 25; 19
Kontrolka NumericUpDown (nr. 4 na rysunku 1):
(Name) - n_maxsize;
Maximum - 2000;
Minimum - 10;
Value - 800;
Location - 189; 70;
Size - 120; 20
Kontrolka Button (nr. 5 na rysunku 1):
(Name) - CreateImg;
Location - 7; 107;
Size - 771; 25
Kontrolka Label (nr. 6 na rysunku 1):
(Name) - lb_progress;
Text - Postęp;
Location - 11; 144;
Size - 40; 13
Kontrolka ProgressBar (nr. 7 na rysunku 1):
(Name) - pb_progress;
Location - 7; 169;
Size - 770; 48;
Komponent FolderBrowserDialog (nr. 8 na rysunku 1):
(Name) - fb_dialog;
Tekst i rozmieszczenie dwóch pozostałych kontrolek Label widoczne jest na rysunku 1, toteż ich nie opisuję.
Pod kontrolkę 3 podpiąć należy zdarzenie Click:
private void bt_browse_Click(object sender, EventArgs e)
{
if (fb_dialog.ShowDialog() == DialogResult.OK) // wyświetlenie okna dialogowego Folder Browser i sprawdzenie, czy wciśnięto przycisk OK
{
tb_path.Text = fb_dialog.SelectedPath; // jeżeli przycisk OK został wciśnięty to pobrać należy ścieżkę do wskazanego folderu
}
}
Kontrolka 5 na rysunku 1 powinna zostać podpięta pod zdarzenie Click:
private void CreateImg_Click(object sender, EventArgs e)
{
System.Threading.Thread thr = new System.Threading.Thread(CreateImgFu); // tworzenie nowego obiektu wątku, parametrem konstruktora jest delegat CreateImgFu
thr.Start(); // uruchomienie wątku
}
Jak widać w powyższym kodzie tworzę nowy wątek i go uruchamiam. Wątkiem tym będzie działanie wewnątrz metody CreateImgFu, której kod będzie wyglądał następująco:
private void CreateImgFu()
{
EnableWnd(false); // blokowanie okna głównego, tak aby użytkownik nie mógł w nim klikać niczego
if (System.IO.Directory.Exists(tb_path.Text)) // sprawdzanie poprawności ścieżki
{
string[] files_jpg = System.IO.Directory.GetFiles(tb_path.Text + (char)(92), "*.jpg"); // pobieranie listy plików jpg
System.IO.Directory.CreateDirectory(tb_path.Text + "\\sm_img"); // tworzenie nowego folderu
int counting = 0; // licznik przetworzonych obrazów
foreach (string i in files_jpg) // iterowanko po ścieżkach dostępu
{
SetProgressValue( counting * 100 / files_jpg.Length); // ustawianie paska postępu
SetProgressText("Przetwarzanie pliku: " + i); // ustawianie tekstu opisującego plik, kótry aktualnie jest przetwarzany
if (System.IO.File.Exists(tb_path.Text + "\\sm_img" + (char)(92) + GetFileName(i))) // jeżeli dany plik już istnieje to nie chcemy go nadpisywać
{
continue; // więc przechodzimy do następnej iteracji bez wykonywania dalszego kodu pętli
}
Image img = Image.FromFile(i); // wczytywanie obrazka z pliku
int max_size = (int)n_maxsize.Value; // pobieranie maksymalnego rozmiaru
double k = (double)max_size / (double)(img.Width < img.Height ? img.Height : img.Width); // ustalanie współczynnika skali
int width = (int)(img.Width * k); // obliczanie szerokości obrazu docelowego
int height = (int)(img.Height * k); // obliczanie wysokości obrazu docelowego
if (width > 0 && height > 0) // sprawdzanie, czy otrzymane wartości nie są czasem mniejsze lub równe 0
{
Bitmap bmp = new Bitmap(img, width, height); // tworzę bitmapę na podstawie obrazka o podanych wymiarach
bmp.Save(tb_path.Text + "\\sm_img" + (char)(92) + GetFileName(i), System.Drawing.Imaging.ImageFormat.Jpeg); // zapisuję obrazek z kompresją Jpeg
}
counting++; // zwiększam licznik o 1
}
SetProgressValue(100); // na koniec progress bar na 100 ustawiam
}
EnableWnd(true); // odblokowuję okno
}
W powyższym kodzie użyłem czterech dodatkowych metod, gdzie trzy z nich są wymagane w celu uzyskania dostępu do zmiennych w nowo utworzonym wątku. Kod źródłowy tych metod jest następujący:
private string GetFileName(string mpath) // wyciąganie nazwy pliku z podanej ścieżki
{
int index = mpath.LastIndexOf((char)(92));
string s = mpath.Substring(index + 1);
return s;
}
private void EnableWnd(bool value) // włączanie / wyłączanie aktywności okna
{
if (InvokeRequired) // jeżeli metoda została wywołana w innym wątku niż w tym, w którym została utworzona to
{
Invoke(new Action<bool>(EnableWnd), value); // trzeba skorzystać z metody Invoke
}
else
{
Enabled = value;
}
}
private void SetProgressText(string text)
{
if (InvokeRequired)
{
Invoke(new Action<string>(SetProgressText), text);
}
else
{
lb_progress.Text = text;
}
}
private void SetProgressValue(int value)
{
if (InvokeRequired)
{
Invoke(new Action<int>(SetProgressValue), value);
}
else
{
pb_progress.Value = value;
}
}
Najtrudniejsze na sam koniec, czyli kompilacja programu i jego uruchomienie.