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

ASP.NET C# 圖片浮水印實作:文字與圖片雙模式完整範例

     編輯:關於C語言

核心類別:System.Drawing 命名空間

  • Image / Bitmap:圖片載入、操作、儲存
  • Graphics:繪圖介面,DrawImage、DrawString
  • Font、Brush、Pen:文字樣式、填充、筆刷
  • GraphicsUnit.Pixel:座標單位

完整 ASP.NET WebForms 實作

.aspx 前端


<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Watermark.aspx.cs" Inherits="Demo.Watermark" %>



    圖片浮水印上傳


    





.aspx.cs 後端


using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Web.UI;

namespace Demo
{
    public partial class Watermark : Page
    {
        protected void Page_Load(object sender, EventArgs e) { }
        
        protected void chkUseText_CheckedChanged(object sender, EventArgs e)
        {
            chkUseImage.Checked = !chkUseText.Checked;
            fuWatermarkImage.Visible = chkUseImage.Checked;
        }
        
        protected void chkUseImage_CheckedChanged(object sender, EventArgs e)
        {
            chkUseText.Checked = !chkUseImage.Checked;
            fuWatermarkImage.Visible = chkUseImage.Checked;
        }
        
        protected void btnUpload_Click(object sender, EventArgs e)
        {
            if (!fuImage.HasFile)
            {
                lblMessage.Text = "請選擇要上傳的圖片";
                return;
            }
            
            try
            {
                // 1. 儲存原始上傳檔案
                string ext = Path.GetExtension(fuImage.FileName).ToLower();
                string[] allowed = { ".jpg", ".jpeg", ".png", ".bmp", ".gif" };
                if (!allowed.Contains(ext)) throw new Exception("不支援的圖片格式");
                
                string fileName = $"{DateTime.Now:yyyyMMddHHmmss}{ext}";
                string uploadPath = Server.MapPath("~/Uploads/");
                Directory.CreateDirectory(uploadPath);
                string originalPath = Path.Combine(uploadPath, fileName);
                fuImage.SaveAs(originalPath);
                
                // 2. 載入圖片並建立 Graphics
                using (Image image = Image.FromFile(originalPath))
                using (Graphics g = Graphics.FromImage(image))
                {
                    // 高品質繪圖設定
                    g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                    g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                    
                    // 繪製原圖 (確保完整繪製到新 Bitmap)
                    g.DrawImage(image, 0, 0, image.Width, image.Height);
                    
                    if (chkUseText.Checked)
                    {
                        // === 文字浮水印 ===
                        string text = txtWatermarkText.Text.Trim();
                        if (string.IsNullOrEmpty(text)) text = "Copyright";
                        
                        // 字體大小依圖片寬度自動調整
                        float fontSize = Math.Max(12, image.Width / 20f);
                        using (Font font = new Font("Arial", fontSize, FontStyle.Bold))
                        using (Brush brush = new SolidBrush(Color.FromArgb(128, 255, 255, 255)))  // 半透明白色
                        using (StringFormat sf = new StringFormat 
                        { 
                            Alignment = StringAlignment.Far, 
                            LineAlignment = StringAlignment.Far 
                        })
                        {
                            // 右下角位置,留 10px 邊距
                            RectangleF rect = new RectangleF(10, 10, image.Width - 20, image.Height - 20);
                            g.DrawString(text, font, brush, rect, sf);
                        }
                    }
                    else if (chkUseImage.Checked && fuWatermarkImage.HasFile)
                    {
                        // === 圖片浮水印 ===
                        using (Image watermark = Image.FromStream(fuWatermarkImage.PostedFile.InputStream))
                        {
                            // 右下角位置
                            int x = image.Width - watermark.Width - 10;
                            int y = image.Height - watermark.Height - 10;
                            
                            // 透明度調整 (可選)
                            ImageAttributes attr = new ImageAttributes();
                            ColorMatrix matrix = new ColorMatrix();
                            matrix.Matrix33 = 0.5f;  // 50% 透明度
                            attr.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
                            
                            g.DrawImage(watermark, 
                                new Rectangle(x, y, watermark.Width, watermark.Height),
                                0, 0, watermark.Width, watermark.Height,
                                GraphicsUnit.Pixel, attr);
                        }
                    }
                    
                    // 3. 儲存結果
                    string resultName = $"{Path.GetFileNameWithoutExtension(fileName)}_wm{ext}";
                    string resultPath = Path.Combine(uploadPath, resultName);
                    
                    // 保持原格式儲存
                    ImageFormat format = ImageFormat.Jpeg;
                    if (ext == ".png") format = ImageFormat.Png;
                    else if (ext == ".bmp") format = ImageFormat.Bmp;
                    else if (ext == ".gif") format = ImageFormat.Gif;
                    
                    image.Save(resultPath, format);
                    
                    // 4. 顯示結果
                    imgResult.ImageUrl = $"~/Uploads/{resultName}";
                    imgResult.Visible = true;
                    lblMessage.Text = "浮水印加入成功!";
                    lblMessage.ForeColor = Color.Green;
                }
                
                // 5. 刪除原始檔 (可選)
                File.Delete(originalPath);
            }
            catch (Exception ex)
            {
                lblMessage.Text = $"錯誤:{ex.Message}";
                lblMessage.ForeColor = Color.Red;
            }
        }
    }
}

關鍵技術細節

1. 文字浮水印進階:斜向重複平鋪


private void DrawTiledTextWatermark(Graphics g, Image image, string text)
{
    using (Font font = new Font("Arial", 24, FontStyle.Bold))
    using (Brush brush = new SolidBrush(Color.FromArgb(80, 200, 200, 200)))
    {
        // 計算文字大小
        SizeF textSize = g.MeasureString(text, font);
        
        // 旋轉 45 度
        g.TranslateTransform(image.Width / 2f, image.Height / 2f);
        g.RotateTransform(-45);
        g.TranslateTransform(-image.Width / 2f, -image.Height / 2f);
        
        // 平鋪繪製
        float stepX = textSize.Width * 1.5f;
        float stepY = textSize.Height * 2f;
        for (float y = -image.Height; y < image.Height * 2; y += stepY)
        {
            for (float x = -image.Width; x < image.Width * 2; x += stepX)
            {
                g.DrawString(text, font, brush, x, y);
            }
        }
        
        // 重置變換
        g.ResetTransform();
    }
}

2. 圖片浮水印:支援透明 PNG


private void DrawImageWatermark(Graphics g, Image image, Image watermark, float opacity = 0.5f)
{
    // 建立帶透明度的 ImageAttributes
    ImageAttributes attr = new ImageAttributes();
    ColorMatrix cm = new ColorMatrix();
    cm.Matrix33 = opacity;  // Alpha 縮放
    attr.SetColorMatrix(cm);
    
    // 置中或指定位置
    int x = (image.Width - watermark.Width) / 2;
    int y = (image.Height - watermark.Height) / 2;
    
    g.DrawImage(watermark, 
        new Rectangle(x, y, watermark.Width, watermark.Height),
        0, 0, watermark.Width, watermark.Height,
        GraphicsUnit.Pixel, attr);
}

3. 非同步處理大量圖片 (ASP.NET Core)


// ASP.NET Core Controller 範例
[HttpPost]
public async Task AddWatermark(IFormFile image, string text, IFormFile watermarkImage)
{
    using (var ms = new MemoryStream())
    {
        await image.CopyToAsync(ms);
        ms.Position = 0;
        using (var img = Image.FromStream(ms))
        using (var g = Graphics.FromImage(img))
        {
            // ... 繪製浮水印邏輯 ...
            
            var resultMs = new MemoryStream();
            img.Save(resultMs, ImageFormat.Png);
            return File(resultMs.ToArray(), "image/png", "watermarked.png");
        }
    }
}

部署注意事項

議題解決方案
GDI+ 非執行緒安全每請求建立獨立 Image/Graphics,勿共用靜態實例
記憶體洩漏所有 Image、Graphics、Font、Brush 必須 using 或手動 Dispose()
伺服器無桌面互動IIS 預設不允許 GDI+ 某些操作,需啟用「允許服務與桌面互動」或改用 ImageSharp/SkiaSharp
高併發效能考慮 ImageSharp (純 managed、跨平台、無 GDI+ 限制)

現代替代方案:ImageSharp


// NuGet: SixLabors.ImageSharp
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Drawing.Processing;
using SixLabors.Fonts;

public byte[] AddWatermark(ImageSharp.Image image, string text)
{
    var font = SystemFonts.CreateFont("Arial", 24, FontStyle.Bold);
    var color = Color.White.WithAlpha(0.5f);
    
    image.Mutate(x => x.DrawText(text, font, color, new PointF(10, 10)));
    
    using (var ms = new MemoryStream())
    {
        image.SaveAsPng(ms);
        return ms.ToArray();
    }
}

本章小結

  • Graphics.DrawString 文字浮水印,Graphics.DrawImage 圖片浮水印
  • Color.FromArgb(alpha, r, g, b) 控制透明度
  • ImageAttributes.ColorMatrix 圖片層級透明度調整
  • 所有 GDI+ 物件必須正確釋放,using 區塊為最佳實務
  • 生產環境高併發建議改用 ImageSharp 或 SkiaSharp 純 managed 函式庫
  • 浮水印位置、大小、透明度、旋轉可依需求參數化配置
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved