title: "怎么使用GraphicsMagick庫的MagickWand類添加半透明水印呢?"
date: 2020-04-05T20:25:01+08:00
description: ""
featured_image: "/static/images/怎么使用GraphicsMagick庫的MagickWand類添加半透明水印呢/GraphicsMagick-Logo.png"
categories: "編程"
tags: ["GraphicsMagick", "MagickWand", "C語言"]
前言
最近做圖片處理功能,參考了各種圖片處理庫的對(duì)比資料稼钩,決定使用GraphicsMagick
這個(gè)庫,并且為了方便使用MagickWand
這個(gè)struct达罗。
基本上一些常用的圖片處理功能都沒啥問題坝撑,卻被半透明圖片水印
這個(gè)功能卡住了。這個(gè)功能很常用也很重要啊粮揉,但是無論是中文還是英文資料巡李,都找不到關(guān)于用MagickWand
這個(gè)struct怎么去處理的線索,硬生生地讓我糾結(jié)了幾天的時(shí)間扶认,終于在今天下午的某個(gè)時(shí)刻侨拦,抱著試試的心態(tài),給解決了辐宾。
解決方案
下面就說說解決方案吧:
-
首先狱从,通過搜索引擎,得知命令行處理
半透明圖片水印
的辦法:/usr/bin/gm composite -geometry +500+450 -dissolve 30 watermark.png input.jpg output.jpg
-
既然命令行可以叠纹,那就說明這個(gè)功能是可以做的季研,通過查看這個(gè)命令處理的源代碼,找到了關(guān)鍵的處理代碼:
http://hg.code.sf.net/p/graphicsmagick/code/file/560875f67e82/magick/command.c#l2971
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); }
思路是先將水印圖片誉察,按設(shè)置的透明度參數(shù)与涡,先設(shè)置成半透明,注意
SetImageOpacity
這個(gè)步驟是不能少的冒窍。然后再使用CompositeImage
這個(gè)方法和DissolveCompositeOp
這個(gè)方式递沪,將水印圖片覆蓋到原來圖片之上。 但是這些方法應(yīng)用的struct是
Image
而不是MagickWand
综液,MagickWand
是Image
的一個(gè)用戶使用友好的封裝款慨,MagickWand
也提供了MagickCompositeImage
這個(gè)方法,和CompositeImage
是類似的谬莹。但是設(shè)置透明度這里卻不知道怎么搞檩奠,遂放棄通過MagickWand
設(shè)置透明度桩了。-
查找
MagickWand
的文檔找不到獲取Image
的方法,但是通過查看MagickWand
的定義發(fā)現(xiàn)了Image
字段埠戳。http://hg.code.sf.net/p/graphicsmagick/code/file/560875f67e82/wand/magick_wand.c#l108
/* 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文件井誉,或者是作者不想暴露里面的字段給用戶,但是為了解決需求整胃,也只能破壞一下封裝了颗圣。
-
將上述的
struct _MagickWand
定義給copy到項(xiàng)目的.h文件里面,先通過watermark->image
獲取到水印圖片MagickWand
的image
字段屁使,按照設(shè)置水印透明度的代碼將水印圖片處理好在岂,然后就可以用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);
后話
事實(shí)上蛮寂,我是通過Rust的ffi調(diào)用GraphicsMagick
的C函數(shù)來處理這個(gè)功能的蔽午,目前沒有找到完善的GraphicsMagick
binding庫,所以只能自己來搞了酬蹋,后面整理好了再開源出來及老。