Chào mọi người.
Đã lâu rồi mình không ghé tranglaptrinhvb.net, nay ghé lại thấy anh thảo có chia sẽ bộ mã nguồn download image hoàng loạt cũng khá thú vị nên mình mang về chia sẽ lại cho mọi người.Như hình, các bạn chỉ cần dán danh sách link vào và bấm nút tải về.
Có thể xem trước (preview) từng hình ảnh.
Dưới đây là video demo ứng dụng:
Full Source Code.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Linq;
namespace ImageDownloader
{
public partial class MainForm : Form
{
private ListBox listBoxUrls;
private TextBox textBoxUrls;
private TextBox textBoxOutputPath;
private Button buttonBrowseOutput;
private Button buttonAddUrls;
private Button buttonRemoveUrl;
private Button buttonDownloadAll;
private Button buttonClearAll;
private ProgressBar progressBar;
private Label labelStatus;
private PictureBox pictureBoxPreview;
private Label labelPreview;
private Panel panelPreview;
private static readonly HttpClient httpClient = new HttpClient();
public MainForm()
{
InitializeComponent();
InitializeHttpClient();
}
private void InitializeComponent()
{
this.SuspendLayout();
// Form properties
this.Text = "Image Downloader - https://laptrinhvb.net";
this.Size = new Size(1000, 600);
this.StartPosition = FormStartPosition.CenterScreen;
this.FormBorderStyle = FormBorderStyle.Sizable;
this.MinimumSize = new Size(800, 500);
// URL input textbox (multiline for pasting multiple URLs)
this.textBoxUrls = new TextBox
{
Location = new Point(12, 12),
Size = new Size(450, 100),
Multiline = true,
ScrollBars = ScrollBars.Vertical,
};
// Add URLs button
this.buttonAddUrls = new Button
{
Location = new Point(470, 12),
Size = new Size(80, 30),
Text = "Add URLs",
UseVisualStyleBackColor = true
};
this.buttonAddUrls.Click += ButtonAddUrls_Click;
// URLs ListBox
this.listBoxUrls = new ListBox
{
Location = new Point(12, 120),
Size = new Size(550, 200),
SelectionMode = SelectionMode.MultiExtended
};
this.listBoxUrls.SelectedIndexChanged += ListBoxUrls_SelectedIndexChanged;
this.listBoxUrls.KeyDown += ListBoxUrls_KeyDown;
// Remove URL button
this.buttonRemoveUrl = new Button
{
Location = new Point(12, 330),
Size = new Size(100, 30),
Text = "Remove Selected",
UseVisualStyleBackColor = true
};
this.buttonRemoveUrl.Click += ButtonRemoveUrl_Click;
// Clear all button
this.buttonClearAll = new Button
{
Location = new Point(120, 330),
Size = new Size(80, 30),
Text = "Clear All",
UseVisualStyleBackColor = true
};
this.buttonClearAll.Click += ButtonClearAll_Click;
// Output path label
Label labelOutput = new Label
{
Location = new Point(12, 375),
Size = new Size(100, 20),
Text = "Output Folder:"
};
// Output path textbox
this.textBoxOutputPath = new TextBox
{
Location = new Point(12, 400),
Size = new Size(450, 23),
Text = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Downloaded_Images")
};
// Browse output button
this.buttonBrowseOutput = new Button
{
Location = new Point(470, 400),
Size = new Size(75, 23),
Text = "Browse",
UseVisualStyleBackColor = true
};
this.buttonBrowseOutput.Click += ButtonBrowseOutput_Click;
// Download all button
this.buttonDownloadAll = new Button
{
Location = new Point(12, 435),
Size = new Size(120, 35),
Text = "Download All",
UseVisualStyleBackColor = true,
BackColor = Color.LightGreen
};
this.buttonDownloadAll.Click += ButtonDownloadAll_Click;
// Progress bar
this.progressBar = new ProgressBar
{
Location = new Point(12, 485),
Size = new Size(550, 23),
Style = ProgressBarStyle.Continuous
};
// Status label
this.labelStatus = new Label
{
Location = new Point(12, 520),
Size = new Size(550, 40),
Text = "Ready to download images...",
AutoSize = false
};
// Preview Panel
this.panelPreview = new Panel
{
Location = new Point(580, 12),
Size = new Size(400, 548),
BorderStyle = BorderStyle.FixedSingle,
BackColor = Color.WhiteSmoke
};
// Preview label
this.labelPreview = new Label
{
Location = new Point(10, 10),
Size = new Size(380, 20),
Text = "Click on a URL to preview image",
TextAlign = ContentAlignment.MiddleCenter,
Font = new Font("Microsoft Sans Serif", 9, FontStyle.Bold)
};
// Picture box for preview
this.pictureBoxPreview = new PictureBox
{
Location = new Point(10, 40),
Size = new Size(380, 500),
SizeMode = PictureBoxSizeMode.Zoom,
BorderStyle = BorderStyle.FixedSingle,
BackColor = Color.White
};
// Add controls to preview panel
this.panelPreview.Controls.AddRange(new Control[] {
this.labelPreview,
this.pictureBoxPreview
});
// Add controls to form
this.Controls.AddRange(new Control[] {
this.textBoxUrls,
this.buttonAddUrls,
this.listBoxUrls,
this.buttonRemoveUrl,
this.buttonClearAll,
labelOutput,
this.textBoxOutputPath,
this.buttonBrowseOutput,
this.buttonDownloadAll,
this.progressBar,
this.labelStatus,
this.panelPreview
});
// Handle form resize
this.Resize += MainForm_Resize;
this.ResumeLayout();
}
private void MainForm_Resize(object sender, EventArgs e)
{
// Adjust preview panel position and size when form is resized
int formWidth = this.ClientSize.Width;
int formHeight = this.ClientSize.Height;
// Adjust main controls width
int mainControlsWidth = Math.Max(300, formWidth - 420);
textBoxUrls.Width = mainControlsWidth - 120;
listBoxUrls.Width = mainControlsWidth;
textBoxOutputPath.Width = mainControlsWidth - 80;
progressBar.Width = mainControlsWidth;
labelStatus.Width = mainControlsWidth;
// Adjust button positions
buttonAddUrls.Left = textBoxUrls.Right + 10;
buttonBrowseOutput.Left = textBoxOutputPath.Right + 10;
// Adjust preview panel
panelPreview.Left = mainControlsWidth + 20;
panelPreview.Width = Math.Max(300, formWidth - mainControlsWidth - 40);
panelPreview.Height = formHeight - 30;
// Adjust preview controls
labelPreview.Width = panelPreview.Width - 20;
pictureBoxPreview.Width = panelPreview.Width - 20;
pictureBoxPreview.Height = panelPreview.Height - 60;
}
private void InitializeHttpClient()
{
httpClient.DefaultRequestHeaders.Add("User-Agent",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
httpClient.Timeout = TimeSpan.FromMinutes(5);
}
private void ButtonAddUrls_Click(object sender, EventArgs e)
{
string urlsText = textBoxUrls.Text.Trim();
if (!string.IsNullOrEmpty(urlsText))
{
string[] urls = urlsText.Split(new char[] { '\n', '\r' },
StringSplitOptions.RemoveEmptyEntries);
int addedCount = 0;
int duplicateCount = 0;
int invalidCount = 0;
foreach (string url in urls)
{
string trimmedUrl = url.Trim();
if (!string.IsNullOrEmpty(trimmedUrl))
{
if (IsValidImageUrl(trimmedUrl))
{
if (!listBoxUrls.Items.Contains(trimmedUrl))
{
listBoxUrls.Items.Add(trimmedUrl);
addedCount++;
}
else
{
duplicateCount++;
}
}
else
{
invalidCount++;
}
}
}
textBoxUrls.Clear();
string statusMessage = $"Added {addedCount} URLs. Total: {listBoxUrls.Items.Count}";
if (duplicateCount > 0)
statusMessage += $" (Skipped {duplicateCount} duplicates)";
if (invalidCount > 0)
statusMessage += $" (Skipped {invalidCount} invalid URLs)";
labelStatus.Text = statusMessage;
if (invalidCount > 0)
{
MessageBox.Show($"Skipped {invalidCount} invalid URLs. Only image URLs with extensions (jpg, jpeg, png, gif, bmp, webp) are accepted.",
"Invalid URLs", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
}
private async void ListBoxUrls_SelectedIndexChanged(object sender, EventArgs e)
{
if (listBoxUrls.SelectedItem != null)
{
string selectedUrl = listBoxUrls.SelectedItem.ToString();
await LoadPreviewImage(selectedUrl);
}
else
{
// Clear preview when no selection
pictureBoxPreview.Image?.Dispose();
pictureBoxPreview.Image = null;
labelPreview.Text = "Click on a URL to preview image";
}
}
private async Task LoadPreviewImage(string url)
{
try
{
labelPreview.Text = "Loading preview...";
pictureBoxPreview.Image?.Dispose();
pictureBoxPreview.Image = null;
// Load image from URL
byte[] imageBytes = await httpClient.GetByteArrayAsync(url);
using (var ms = new MemoryStream(imageBytes))
{
Image image = Image.FromStream(ms);
pictureBoxPreview.Image = new Bitmap(image); // Create a copy
}
// Update label with image info
if (pictureBoxPreview.Image != null)
{
string fileName = GetFileNameFromUrl(url);
labelPreview.Text = $"{fileName} ({pictureBoxPreview.Image.Width}x{pictureBoxPreview.Image.Height})";
}
}
catch (Exception ex)
{
pictureBoxPreview.Image?.Dispose();
pictureBoxPreview.Image = null;
labelPreview.Text = $"Failed to load preview: {ex.Message}";
}
}
private void ListBoxUrls_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Delete)
{
ButtonRemoveUrl_Click(sender, e);
}
}
private void ButtonRemoveUrl_Click(object sender, EventArgs e)
{
if (listBoxUrls.SelectedItems.Count > 0)
{
var itemsToRemove = new List<object>();
foreach (object item in listBoxUrls.SelectedItems)
{
itemsToRemove.Add(item);
}
foreach (object item in itemsToRemove)
{
listBoxUrls.Items.Remove(item);
}
labelStatus.Text = $"Removed {itemsToRemove.Count} URLs. Total: {listBoxUrls.Items.Count}";
// Clear preview if no items selected
if (listBoxUrls.SelectedItems.Count == 0)
{
pictureBoxPreview.Image?.Dispose();
pictureBoxPreview.Image = null;
labelPreview.Text = "Click on a URL to preview image";
}
}
}
private void ButtonClearAll_Click(object sender, EventArgs e)
{
if (listBoxUrls.Items.Count > 0)
{
var result = MessageBox.Show("Are you sure you want to clear all URLs?",
"Clear All", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (result == DialogResult.Yes)
{
listBoxUrls.Items.Clear();
labelStatus.Text = "All URLs cleared.";
// Clear preview
pictureBoxPreview.Image?.Dispose();
pictureBoxPreview.Image = null;
labelPreview.Text = "Click on a URL to preview image";
}
}
}
private void ButtonBrowseOutput_Click(object sender, EventArgs e)
{
using (FolderBrowserDialog folderDialog = new FolderBrowserDialog())
{
folderDialog.Description = "Select output folder for downloaded images";
folderDialog.SelectedPath = textBoxOutputPath.Text;
if (folderDialog.ShowDialog() == DialogResult.OK)
{
textBoxOutputPath.Text = folderDialog.SelectedPath;
}
}
}
private async void ButtonDownloadAll_Click(object sender, EventArgs e)
{
if (listBoxUrls.Items.Count == 0)
{
MessageBox.Show("No URLs to download!", "No URLs",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
string outputPath = textBoxOutputPath.Text.Trim();
if (string.IsNullOrEmpty(outputPath))
{
MessageBox.Show("Please select an output folder!", "No Output Folder",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
try
{
// Create output directory if it doesn't exist
if (!Directory.Exists(outputPath))
{
Directory.CreateDirectory(outputPath);
}
// Disable controls during download
SetControlsEnabled(false);
progressBar.Maximum = listBoxUrls.Items.Count;
progressBar.Value = 0;
int successCount = 0;
int failCount = 0;
for (int i = 0; i < listBoxUrls.Items.Count; i++)
{
string url = listBoxUrls.Items[i].ToString();
labelStatus.Text = $"Downloading {i + 1} of {listBoxUrls.Items.Count}: {Path.GetFileName(url)}";
try
{
await DownloadImage(url, outputPath);
successCount++;
}
catch (Exception ex)
{
failCount++;
// Log error but continue with other downloads
Console.WriteLine($"Failed to download {url}: {ex.Message}");
}
progressBar.Value = i + 1;
Application.DoEvents(); // Update UI
}
labelStatus.Text = $"Download completed! Success: {successCount}, Failed: {failCount}";
if (successCount > 0)
{
var result = MessageBox.Show($"Download completed!\n\nSuccess: {successCount}\nFailed: {failCount}\n\nOpen output folder?",
"Download Complete", MessageBoxButtons.YesNo, MessageBoxIcon.Information);
if (result == DialogResult.Yes)
{
System.Diagnostics.Process.Start("explorer.exe", outputPath);
}
}
}
catch (Exception ex)
{
MessageBox.Show($"Error during download: {ex.Message}", "Download Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
labelStatus.Text = "Download failed!";
}
finally
{
SetControlsEnabled(true);
progressBar.Value = 0;
}
}
private async Task DownloadImage(string url, string outputPath)
{
try
{
byte[] imageBytes = await httpClient.GetByteArrayAsync(url);
// Generate filename from URL
string fileName = GetFileNameFromUrl(url);
string fullPath = Path.Combine(outputPath, fileName);
// Handle duplicate filenames
int counter = 1;
string originalFileName = Path.GetFileNameWithoutExtension(fileName);
string extension = Path.GetExtension(fileName);
while (File.Exists(fullPath))
{
fileName = $"{originalFileName}_{counter}{extension}";
fullPath = Path.Combine(outputPath, fileName);
counter++;
}
await Task.Run(() => File.WriteAllBytes(fullPath, imageBytes));
}
catch (HttpRequestException ex)
{
throw new Exception($"Network error: {ex.Message}");
}
catch (TaskCanceledException)
{
throw new Exception("Download timeout");
}
catch (Exception ex)
{
throw new Exception($"Download failed: {ex.Message}");
}
}
private string GetFileNameFromUrl(string url)
{
try
{
Uri uri = new Uri(url);
string fileName = Path.GetFileName(uri.LocalPath);
// If no filename in URL, generate one
if (string.IsNullOrEmpty(fileName) || !fileName.Contains("."))
{
string extension = GetImageExtensionFromUrl(url);
fileName = $"image_{DateTime.Now:yyyyMMdd_HHmmss}_{Guid.NewGuid().ToString("N").Substring(0, 8)}{extension}";
}
// Remove invalid characters
string invalidChars = new string(Path.GetInvalidFileNameChars());
foreach (char c in invalidChars)
{
fileName = fileName.Replace(c, '_');
}
return fileName;
}
catch
{
return $"image_{DateTime.Now:yyyyMMdd_HHmmss}.jpg";
}
}
private string GetImageExtensionFromUrl(string url)
{
string[] extensions = { ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp" };
foreach (string ext in extensions)
{
if (url.ToLower().Contains(ext))
return ext;
}
return ".jpg"; // Default extension
}
private bool IsValidImageUrl(string url)
{
if (string.IsNullOrWhiteSpace(url))
return false;
try
{
Uri uri = new Uri(url);
if (uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps)
return false;
string[] validExtensions = { ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp" };
string lowerUrl = url.ToLower();
return validExtensions.Any(ext => lowerUrl.Contains(ext)) ||
lowerUrl.Contains("image") ||
lowerUrl.Contains("photo") ||
lowerUrl.Contains("pic");
}
catch
{
return false;
}
}
private void SetControlsEnabled(bool enabled)
{
buttonAddUrls.Enabled = enabled;
buttonRemoveUrl.Enabled = enabled;
buttonClearAll.Enabled = enabled;
buttonDownloadAll.Enabled = enabled;
buttonBrowseOutput.Enabled = enabled;
textBoxUrls.Enabled = enabled;
listBoxUrls.Enabled = enabled;
}
protected override void OnFormClosed(FormClosedEventArgs e)
{
// Dispose preview image
pictureBoxPreview.Image?.Dispose();
httpClient?.Dispose();
base.OnFormClosed(e);
}
}
// Program entry point
}
Chúc mọi người thành công. Mọi người có thể
Download Full Source Code bên dưới để về tìm hiểu và vọc vạch nhé.Download Source Code
Theo LapTrinhVB.Net

0 Comments:
Post a Comment