首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> 關於ASP.NET

ASP.NET 上傳圖片並生成縮略圖完整實作:GDI+ 高品質縮放與資源管理

     編輯:關於ASP.NET

完整上傳與縮略圖生成流程

  1. 驗證上傳檔案為圖片類型 (ContentType 以 "image" 開頭)。
  2. 讀取上傳檔案輸入流建立 System.Drawing.Image 物件。
  3. 計算縮略圖尺寸:保持原圖長寬比,限制最大寬/高 (如 100x100)。
  4. 建立目標 Bitmap,使用 Graphics 高品質插值模式繪製縮圖。
  5. 分別儲存原圖與縮略圖 (JPEG 格式),檔名含時間戳避免衝突。
  6. 嚴格釋放所有非受控資源 (Image、Graphics、Bitmap)。

核心程式碼 (C#)

protected void btnUpload_Click(object sender, EventArgs e)
{
    // 1. 驗證檔案類型
    HttpPostedFile postedFile = uploadFile.PostedFile;
    if (postedFile == null || postedFile.ContentLength == 0)
    {
        lblMsg.Text = "請選擇檔案";
        return;
    }
    if (!postedFile.ContentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
    {
        lblMsg.Text = "僅允許上傳圖片檔案";
        return;
    }

    // 2. 讀取原圖
    Image originalImage;
    try
    {
        using (Stream inputStream = postedFile.InputStream)
        {
            originalImage = Image.FromStream(inputStream);
        }
    }
    catch (Exception ex)
    {
        lblMsg.Text = "圖片讀取失敗: " + ex.Message;
        return;
    }

    int origW = originalImage.Width;
    int origH = originalImage.Height;
    const int maxThumbSize = 100;

    // 3. 計算縮略圖尺寸 (保持比例)
    int thumbW, thumbH;
    if (origW >= origH)
    {
        thumbW = maxThumbSize;
        thumbH = (int)Math.Floor((double)origH * maxThumbSize / origW);
    }
    else
    {
        thumbH = maxThumbSize;
        thumbW = (int)Math.Floor((double)origW * maxThumbSize / origH);
    }

    // 4. 生成高品質縮略圖
    Bitmap thumbBitmap = null;
    Graphics g = null;
    try
    {
        thumbBitmap = new Bitmap(thumbW, thumbH);
        g = Graphics.FromImage(thumbBitmap);
        
        // 關鍵:高品質插值與平滑模式
        g.InterpolationMode = InterpolationMode.HighQualityBicubic; // 雙三次插值,品質最佳
        g.SmoothingMode = SmoothingMode.HighQuality;
        g.PixelOffsetMode = PixelOffsetMode.HighQuality;
        g.CompositingQuality = CompositingQuality.HighQuality;
        
        g.Clear(Color.Transparent); // 透明背景
        g.DrawImage(originalImage, 
                    new Rectangle(0, 0, thumbW, thumbH), 
                    new Rectangle(0, 0, origW, origH), 
                    GraphicsUnit.Pixel);
    }
    finally
    {
        if (g != null) g.Dispose();
    }

    // 5. 產生唯一檔名 (yyyyMMddHHmmssfff)
    string timestamp = DateTime.Now.ToString("yyyyMMddHHmmssfff");
    string uploadDir = Server.MapPath("~/Uploads/");
    if (!Directory.Exists(uploadDir)) Directory.CreateDirectory(uploadDir);
    
    string originalPath = Path.Combine(uploadDir, "orig_" + timestamp + ".jpg");
    string thumbPath = Path.Combine(uploadDir, "thumb_" + timestamp + ".jpg");

    // 6. 儲存 (統一轉 JPEG,品質 90%)
    ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");
    EncoderParameters ep = new EncoderParameters(1);
    ep.Param[0] = new EncoderParameter(Encoder.Quality, 90L);

    try
    {
        originalImage.Save(originalPath, jpegCodec, ep);
        thumbBitmap.Save(thumbPath, jpegCodec, ep);
        lblMsg.Text = "上傳成功!原圖: " + Path.GetFileName(originalPath) + " 縮圖: " + Path.GetFileName(thumbPath);
        
        // 顯示縮圖預覽
        imgPreview.ImageUrl = "~/Uploads/" + Path.GetFileName(thumbPath);
    }
    catch (Exception ex)
    {
        lblMsg.Text = "儲存失敗: " + ex.Message;
    }
    finally
    {
        // 7. 嚴格釋放資源 (關鍵!)
        originalImage.Dispose();
        if (thumbBitmap != null) thumbBitmap.Dispose();
    }
}

private ImageCodecInfo GetEncoderInfo(string mimeType)
{
    foreach (ImageCodecInfo codec in ImageCodecInfo.GetImageEncoders())
    {
        if (codec.MimeType == mimeType) return codec;
    }
    return null;
}

關鍵技術細節解析

技術點說明最佳實務
InterpolationMode縮放演算法HighQualityBicubic (雙三次) 品質最佳;HighQualityBilinear 次之;NearestNeighbor 最快但鋸齒嚴重
SmoothingMode邊緣平滑HighQuality 配合插值模式
CompositingQuality合成品質HighQuality 減少色帶
PixelOffsetMode像素偏移HighQuality 提升銳度
Encoder.QualityJPEG 壓縮品質 (0-100)85-95 平衡檔案大小與視覺品質
資源釋放非受控 GDI+ 物件必須在 finally 區塊 Dispose(),否則導致 GDI+ 物件洩漏、程序崩潰

進階擴展:支援多種輸出格式與儲存策略

  • 保留原始格式:依 postedFile.ContentType 決定 Encoder (PNG 保留透明、JPEG 相片)。
  • 雲端儲存整合:儲存至 Azure Blob / AWS S3,回傳 CDN URL,Web 伺服器無狀態化。
  • 非同步處理:大檔案上傳佇列至背景工作 (Hangfire/Quartz/HostedService) 生成多種尺寸縮圖 (100x100, 300x300, 800x600),避免阻塞請求執行緒。
  • 影片縮圖:搭配 FFmpeg (NReco.VideoConverter) 擷取關鍵幀生成縮圖。

安全性檢核清單

  • [ ] 驗證 ContentType **且** 檔案簽名 (Magic Bytes) 確認為圖片。
  • [ ] 限制上傳檔案大小 (<httpRuntime maxRequestLength="10240" /> 10MB)。
  • [ ] 儲存目錄**不可執行**腳本 (IIS 移除執行權限、web.config 設定 <handlers> 封鎖)。
  • [ ] 檔名使用 GUID/時間戳,**不可**使用用戶原始檔名 (防止路徑遍歷、覆蓋)。
  • [ ] 考慮掃描惡意代碼 (ClamAV/Windows Defender 整合)。

結語

ASP.NET 圖片上傳與縮略圖生成的核心在於:**正確驗證、高品質 GDI+ 繪製 (InterpolationMode.HighQualityBicubic)、嚴格資源釋放 (Dispose)、安全儲存策略**。掌握這些細節,能避免常見的模糊縮圖、GDI+ 記憶體洩漏、上傳目錄被植入惡意腳本等生產環境災難。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved