怎麼使用GraphicsMagick庫的MagickWand類添加半透明水印呢?

前言

最近作圖片處理功能,參考了各類圖片處理庫的對比資料,決定使用GraphicsMagick這個庫,而且爲了方便使用MagickWand這個struct。c#

基本上一些經常使用的圖片處理功能都沒啥問題,卻被半透明圖片水印這個功能卡住了。這個功能很經常使用也很重要啊,可是不管是中文仍是英文資料,都找不到關於用MagickWand這個struct怎麼去處理的線索,硬生生地讓我糾結了幾天的時間,終於在今天下午的某個時刻,抱着試試的心態,給解決了。bash

解決方案

下面就說說解決方案吧:函數

  1. 首先,經過搜索引擎,得知命令行處理半透明圖片水印的辦法:搜索引擎

    /usr/bin/gm composite -geometry +500+450 -dissolve 30 watermark.png input.jpg output.jpg
  2. 既然命令行能夠,那就說明這個功能是能夠作的,經過查看這個命令處理的源代碼,找到了關鍵的處理代碼:.net

    http://hg.code.sf.net/p/graph...命令行

    static MagickPassFail CompositeImageList(ImageInfo *image_info,Image **image,
    Image *composite_image,Image *mask_image,CompositeOptions *option_info,
    ExceptionInfo *exception)
    {
    // ...
              if (option_info->compose == DissolveCompositeOp)
              {
                  register PixelPacket
                  *q;
    
                  /*
                  Create mattes for dissolve.
                  */
                  if (!composite_image->matte)
                    SetImageOpacity(composite_image,OpaqueOpacity);
                  for (y=0; y < (long) composite_image->rows; y++)
                  {
                    q=GetImagePixels(composite_image,0,y,composite_image->columns,1);
                    if (q == (PixelPacket *) NULL)
                        break;
                    for (x=0; x < (long) composite_image->columns; x++)
                    {
                        q->opacity=(Quantum)
                        ((((unsigned long) MaxRGB-q->opacity)*option_info->dissolve)/100.0);
                        q++;
                    }
                    if (!SyncImagePixels(composite_image))
                        break;
                  }
              }
    // ...
               status&=CompositeImage(*image,option_info->compose,
                 composite_image,geometry.x,geometry.y);
    }

    思路是先將水印圖片,按設置的透明度參數,先設置成半透明,注意SetImageOpacity這個步驟是不能少的。而後再使用CompositeImage這個方法和DissolveCompositeOp這個方式,將水印圖片覆蓋到原來圖片之上。code

  3. 可是這些方法應用的struct是Image而不是MagickWandMagickWandImage的一個用戶使用友好的封裝,MagickWand也提供了MagickCompositeImage這個方法,和CompositeImage是相似的。可是設置透明度這裏殊不知道怎麼搞,遂放棄經過MagickWand設置透明度。
  4. 查找MagickWand的文檔找不到獲取Image的方法,可是經過查看MagickWand的定義發現了Image字段。索引

    http://hg.code.sf.net/p/graph...圖片

    /*
      Typedef declarations.
    */
    struct _MagickWand
    {
      char
        id[MaxTextExtent];
    
      ExceptionInfo
        exception;
    
      ImageInfo
        *image_info;
    
      QuantizeInfo
        *quantize_info;
    
      Image
        *image,             /* Current working image */
        *images;            /* Whole image list */
    
      unsigned int
        iterator;
    
      unsigned long
        signature;
    };

    惋惜定義是在.c文件而不是.h文件,或者是做者不想暴露裏面的字段給用戶,可是爲了解決需求,也只能破壞一下封裝了。ci

  5. 將上述的struct _MagickWand定義給copy到項目的.h文件裏面,先經過watermark->image獲取到水印圖片MagickWandimage字段,按照設置水印透明度的代碼將水印圖片處理好,而後就能夠用MagickWandMagickCompositeImage方法去將水印圖片覆蓋到原圖片了。

    完整代碼參考如下:

    MagickWand *input;
    MagickWand *watermark;
    
    //...
    
    Image *composite_image = watermark->image;
    
    register PixelPacket *q;
    
    /*
    Create mattes for dissolve.
    */
    if (!composite_image->matte)
      SetImageOpacity(composite_image,OpaqueOpacity);
    for (y=0; y < (long) composite_image->rows; y++)
    {
      q=GetImagePixels(composite_image,0,y,composite_image->columns,1);
      if (q == (PixelPacket *) NULL)
          break;
      for (x=0; x < (long) composite_image->columns; x++)
      {
          q->opacity=(Quantum)
          ((((unsigned long) MaxRGB-q->opacity)*option_info->dissolve)/100.0);
          q++;
      }
      if (!SyncImagePixels(composite_image))
          break;
    }
    
    MagickCompositeImage(input, watermark, DissolveCompositeOp, 500, 450);

後話

事實上,我是經過Rust的ffi調用GraphicsMagick的C函數來處理這個功能的,目前沒有找到完善的GraphicsMagick binding庫,因此只能本身來搞了,後面整理好了再開源出來。

相關文章
相關標籤/搜索