【问题标题】:Most Efficient Way To Watermark Image C# On The Fly?C#动态水印图像的最有效方法?
【发布时间】:2010-12-02 15:25:02
【问题描述】:

我有一个用 asp.net c# (Webforms) 构建的电子商务商店,而且很多新产品图片很难获得,所以我想用我们的徽标或域名给它们加水印。

只有下载图片和添加水印的产品太多了,图像编辑经验有限的用户会上传新的(所以他们不知道如何添加水印)。

所以我想这只是让我使用 HttpHandler 吗?是/否?如果是这样,您能否提供一些关于添加水印的最有效方法的见解(最好是 C# 中的代码示例),考虑到 某些页面将有大约 20 张图像 (都需要加水印)

【问题讨论】:

    标签: c# asp.net webforms watermark


    【解决方案1】:

    我将Graphicsobject 获取到jpeg,然后在该项目的顶部绘制水印,并使用水印再次保存:

    using (Image image = Image.FromFile("myImage.jpg"))
    using(Graphics g = Graphics.FromImage( image)){
      g.DrawImage( myWaterMarkImage, myPosition);
      image.Save(myFilename);
    }
    

    【讨论】:

    • 这样做的问题是,它可能会由于 jpeg 重新压缩而降低整个图像的图像质量,而不仅仅是水印所在的块。但我不知道是否有一种简单的方法可以做得更好。
    • 虽然它会降低图像的质量,但只要它只做一次就不会有太大的问题,尤其是在普通网络图像的大小/分辨率方面。当然,除非压缩率太高,否则最终会导致 Paint 产生的那种混乱。
    【解决方案2】:

    这看起来可能会有所帮助:

    http://www.switchonthecode.com/tutorials/csharp-snippet-tutorial-how-to-draw-text-on-an-image

    虽然它侧重于文本,但我相信只要稍加修改,您也可以在其中添加图形。

    一旦你有了一个实现,你可以在每个视图中调用一次,或者在保存文件之前添加。

    【讨论】:

      【解决方案3】:

      这里是一个示例 HttpHandler

      /// <summary>
      /// Summary description for $codebehindclassname$
      /// </summary>
      [WebService(Namespace = "http://tempuri.org/")]
      [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
      public class ImageHandler : IHttpHandler
      {
      
          public void ProcessRequest(HttpContext context)
          {
              string imageName = string.Empty;
              string physicalPath = string.Empty;
              Image image = null;
              Image thumbnailImage = null;
              Bitmap bitmap = null;
              using (MemoryStream memoryStream = new MemoryStream())
              {
                  string actionName = context.Request.QueryString["Image"];
                  string opacity = context.Request.QueryString["Opacity"];
                  int opacityPercent = int.Parse(opacity);
                  Color waterMarkColor = Color.Gray;
                  switch (actionName)
                  {
                      case "BlueHills":
                          string myCompany = "My Company Name";
                          Font font = new Font("Times New Roman", 8f);
      
                          context.Response.ContentType = "image/png";
                          bitmap = Resources.Resources.BlueHills;
                          Graphics g = Graphics.FromImage(bitmap);
                          Brush myBrush = new SolidBrush(Color.FromArgb(opacityPercent, waterMarkColor));
                          SizeF sz = g.MeasureString(myCompany, font);
                          int X = (int)(bitmap.Width - sz.Width) / 2;
                          int Y = (int)(sz.Height) / 2;
                          g.DrawString(myCompany, font, myBrush, new Point(X, Y));
                          bitmap.Save(memoryStream, ImageFormat.Png);
                          break;
                      default:
                          string test = actionName;
                          break;
                  }
      
                  context.Response.BinaryWrite(memoryStream.GetBuffer());
                  memoryStream.Close();
                  if (image != null) { image.Dispose(); }
                  if (thumbnailImage != null) { thumbnailImage.Dispose(); }
                  if (bitmap != null) { bitmap.Dispose(); }
              }
          }
      
          public bool IsReusable
          {
              get
              {
                  return false;
              }
          }
      }
      

      并且可以这样调用:

      <asp:Image ID="Image1" runat="server" ImageUrl="~/ImageHandler.ashx?Image=BlueHills&Opacity=50" />
      

      【讨论】:

        【解决方案4】:

        我建议您查看 WPF 类来完成这项工作(GDI+ 在 Web 上下文中已弃用)。

        方式(我不知道是否是最好的方式,但我已经这样做并且效果很好)类似于:

        // Load the original image
        BitmapImage image = new BitmapImage();
        image.BeginInit();
        image.CacheOption = BitmapCacheOption.OnLoad;
        image.UriSource = new Uri(physical_imagepath);
        image.EndInit();
        
        // Create a final render image
        RenderTargetBitmap final = new RenderTargetBitmap(yourNeededWidth, yourNeededHeight, yourDpiDefault, yourDpiDefault, PixelFormats.Default);
        
        DrawingVisual dv = new DrawingVisual();
        
        using (DrawingContext dc = dv.RenderOpen())
        {
            Rect rectImage = new Rect(0, 0, (double)image.PixelWidth, (double)image.PixelHeight);
            dc.DrawImage(image, rectImage);
        
            // Load the bitmap of the watermark
            BitmapImage watermark = new BitmapImage();
            watermark.BeginInit();
            watermark.CacheOption = BitmapCacheOption.OnLoad;
            watermark.UriSource = new Uri(physical_logopath);
            watermark.EndInit();
        
            // Defines the watermark box
            Rect rectWatermark = new Rect(0, 0, (double)watermark.PixelWidth, (double)watermark.PixelHeight);
        
            /* use rectWatermark.X and rectWatermark.Y to move your watermark box around on the final image */
        
            dc.DrawImage(watermark, rectWatermark);
        }
        
        final.Render(dv);
        
        // And then serve the final Bitmap to the client
        

        当然都写成HttpHandler。 以上代码未经测试。

        (小广告:我发布了一个类似工作的CodeCanyon Item)。

        【讨论】:

        • 这是一个旧答案,但我希望你能看到:为什么你使用 96 作为 dpi 值?
        • 这是任意的。我不得不为输出选择一个固定的 dpi,许多人认为 96dpi 将取代实际的 Web 标准(72dpi)......但是是的,没有真正的原因
        【解决方案5】:

        这不是一个答案,而是一些提示:

        1. Jpeg 不支持透明度,最好的办法是添加水印图像并将其设为非常浅的灰色。
        2. 使用通用处理程序 (.ashx),它非常轻量级,无需向 web.config 文件添加任何内容。
        3. 如果每页要超过 20 张图片,那么我建议您在获取图片时添加水印。这是每张图片的一次性费用,可以更快地加载包含图片的页面。

        我不能保证添加水印的最有效方式,但如果您使用提示 #3,它就变得不那么重要了,因为您将只对每张图像执行一次操作。我可能只是使用 System.Drawing 命名空间来做到这一点;请务必处理掉您使用的资源(图像、图形等),尽管我确信那里有一些库可以更好地工作。

        【讨论】:

        • 添加水印的中间阶段不受 JPEG 文件的限制 - 因此您可以在图像上放置透明水印。
        • 你是对的,虽然我在加载一种类型的图像并保存为另一种类型(图像质量问题)时对 System.Drawing 库有过不好的体验,所以我不建议这样做所以。此外,如果您要保存为允许透明的格式,它可以是 gif(这对照片质量的图像不利)或 png(某些旧浏览器不支持)。我不认为自己是成像专家,这些观察是基于我过去的经验。
        【解决方案6】:

        如果您能负担得起存储成本,对任何“动态图像水印”的明显优化是缓存“水印”图像。因此,wartermarking 操作本身的效率并不重要。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-02-15
          • 2011-07-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多