最近作圖片處理功能,參考了各類圖片處理庫的對比資料,決定使用GraphicsMagick
這個庫,而且爲了方便使用MagickWand
這個struct。c#
基本上一些經常使用的圖片處理功能都沒啥問題,卻被半透明圖片水印
這個功能卡住了。這個功能很經常使用也很重要啊,可是不管是中文仍是英文資料,都找不到關於用MagickWand
這個struct怎麼去處理的線索,硬生生地讓我糾結了幾天的時間,終於在今天下午的某個時刻,抱着試試的心態,給解決了。bash
下面就說說解決方案吧:函數
首先,經過搜索引擎,得知命令行處理半透明圖片水印
的辦法:搜索引擎
/usr/bin/gm composite -geometry +500+450 -dissolve 30 watermark.png input.jpg output.jpg
既然命令行能夠,那就說明這個功能是能夠作的,經過查看這個命令處理的源代碼,找到了關鍵的處理代碼:.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
Image
而不是MagickWand
,MagickWand
是Image
的一個用戶使用友好的封裝,MagickWand
也提供了MagickCompositeImage
這個方法,和CompositeImage
是相似的。可是設置透明度這裏殊不知道怎麼搞,遂放棄經過MagickWand
設置透明度。查找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
將上述的struct _MagickWand
定義給copy到項目的.h文件裏面,先經過watermark->image
獲取到水印圖片MagickWand
的image
字段,按照設置水印透明度的代碼將水印圖片處理好,而後就能夠用MagickWand
的MagickCompositeImage
方法去將水印圖片覆蓋到原圖片了。
完整代碼參考如下:
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庫,因此只能本身來搞了,後面整理好了再開源出來。