上篇文章所述,最近有一个项目,需要在linux环境下生成透明的gif图。考虑到画图的质量,采用了cairo来画图。但是cairo并没有gif格式,所以必须使用一个库来进行格式的转换。之前是采用cximage,千辛万苦编好cximage库之后(参考64位Linux下编译cximage动态库),悲催的发现,cximage的构造方法会使cairo绘图过程中无法分配内存。因此,不得不放弃cximage,寻找别的库。

        很快,发现另外一个很强大的图像处理库ImageMagick,除了直接使用命令行来进行图像处理,还对C提供了一个API库供使用(参考官网关于API的介绍http://www.imagemagick.org/script/magick-wand.php?cm_mc_uid=55515229409514829062783&cm_mc_sid_50200000=1487237946)。遍寻网络,想走捷径,找到编好的so库,然而,残酷的事实证明,只能自己编译。花了将近一个星期,才编译好可用的库,过程如下:

        1、下载可用的ImageMagick包,官网地址:http://www.imagemagick.org/script/install-source.php#unix,官网中不仅提供了下载地址,还有安装步骤。

 需要注意的是,默认安装目录是/usr/local/。项目需要,我设置了自定义安装目录为/usr/。命令如下:         

tar xvzf ImageMagick.tar.gz
cd ImageMagick-7.0.5
 ./configure --prefix=/usr
 make
make install

      查看是否安装成功,输入如下命令行

convert --version
      显示如下:

       有时,可能会碰到显示连接不到动态库的错误,此时需要输入如下命令,即可

/sbin/ldconfig /usr/lib
      请注意,我是自定义目录为/usr/lib。如果是默认 目录的,请输入

/sbin/ldconfig /usr/local/lib

      2、由此安装结束。尝试通过命令行进行图片转换,查看是否有效:

convert 1.png 1.gif
      这条命令的意思是将当前目录下1.png转换为1.gif。

      然而,输入命令后显示错误

no decode delegate for this image format PNG
       意思是 没有PNG这种格式

       出现这种类型的error时,需要自己安装一下缺失的格式包,可以通过安装二进制方式,也可以自己编译源代码。我选择的是编译源代码

       下载页面地址:https://sourceforge.net/projects/libpng/files/。

       下载最新版本libpng1.6.28,安装、编译后,运行

tar xvzf libpng-1.6.28.tar.xz
cd libpng-1.6.28
 ./configure --prefix=/usr
 make
make install
         实际上,在make时,我这里就出现了一个error:

libpng16.so: undefined reference to `inflateValidate'

         出现这个error的原因是,你 安装的zlib版本和png版本有冲突。这就需要你多尝试几个版本的png了。最后,在我电脑上安装成功的版本是libpng-1.2.57,

我的zlib版本是1.2.11。

        注意:安装成功后,需要重新安装imagemagick,进入imagemagick目录,清空之前的所有操作,然后重新make,命令如下:

make uninstall
make distclean
./configure --prefix=/usr
make
make install

         然后尝试转换图片格式,发现可以成功转换了!

       3、基本工作算是完成了,接下来需要在我们的C程序中引用imagemagick API 方法了。

             首先:在makefile中,引入imagemagick动态库,注意,在usr/lib目录下,可以看到生成了两个动态库,其中“libMagickCore-7.Q16HDRI.so”这个是底层库,

“libMagickWand-7.Q16HDRI.so”这个是提供了基本图像操作的API库,我们需要的就是这个库。


完整的makefile如下:

CC = gcc
XX = g++
LD = ld
AR = ar

CFLAGS = -fPIC -Wall -O  -DLINUX -DPTHREADS 
LDFLAGS =   -shared  -L/usr/lib64  -lcairo -ldl -lxml2 -lglib-2.0 -L/usr/lib -lMagickWand-7.Q16HDRI
ARFLAGS = -rcs

DIR_INC = ../include
DIR2_INC = ../include/glib-2.0
DIR3_INC = ../include/cairo
DIR4_INC = ../ImageMagick/ImageMagick-7.0.4-9
DIR2_LIB = ../Demo
DIR_SYS = /lib64

LIB_NAME  = libs

INC = -I${DIR_INC} -I${DIR2_INC} -I${DIR3_INC} -I${DIR4_INC}

%.o:%.cpp
	$(XX) $(CFLAGS)  $(INC) -c $< -o $@

SOURCES = $(wildcard *.cpp)
OBJS = *.o 

SHARE_LIB   = $(LIB_NAME).so
DYNAMIC_LIB = $(LIB_NAME).a 

all:$(OBJS)
	$(LD) $(LDFLAGS) -o $(SHARE_LIB) $(OBJS) 
	#${AR} ${ARFLAGS} $(DYNAMIC_LIB) $(OBJS)
	cp $(SHARE_LIB) $(DIR2_LIB)
	cp $(SHARE_LIB) $(DIR_SYS)
	#cp $(DYNAMIC_LIB) $(DIR2_LIB)

clean:
	rm -rf *.o $(SHARE_LIB) $(DYNAMIC_LIB)

然后在C程序中引入头文件,就可以使用它的方法了。下面是从官网中参考写的一个例子,是将当前目录下一个png图片转换成gif格式,并做透明处理。

#include "MagickWand/MagickWand.h"


    void ThrowWandException(MagickWand *wand) 
    { 
	    char *description; 
 
        ExceptionType severity; 
 
        description=MagickGetException(wand,&severity); 
        printf(description);
	printf("\n");
        description=(char *) MagickRelinquishMemory(description); 
    }

	void MakeSealTransparentAndConvertToGIF()
	{
	    MagickBooleanType status;
	    MagickWand *magick_wand = NULL;
	    // Set default fuzz to zero (see below)
	    double fuzz = 0.;
	    PixelWand *target;

	    MagickWandGenesis();

	    magick_wand = NewMagickWand();
		status = MagickReadImageBlob(magick_wand, eseal_data, eseal_data_length);
		if (status == MagickFalse)
            ThrowWandException(magick_wand);

	    // A larger fuzz value allows more colours "near" white to be
	    // modified. A fuzz of zero only allows an exact match with the 
	    // given colour
	    fuzz = 10.;
    	// Set up the pixelwand containing the colour to be "targeted"
    	// by transparency
	    target = NewPixelWand();
	    PixelSetColor(target,"white");
	    // Change the transparency of all colours which match target (with
	    // fuzz applied). In this case they are made completely transparent (0)
	    // but you can set this to any value from 0 to 1.
    	status = MagickTransparentPaintImage(magick_wand,target,0,fuzz,MagickFalse);
		if (status == MagickFalse)
            ThrowWandException(magick_wand);

	    status = MagickWriteImage(magick_wand,"cairo2.gif");
		if (status == MagickFalse)
            ThrowWandException(magick_wand);
	   /* Clean up */
	    if(magick_wand)magick_wand = DestroyMagickWand(magick_wand);
	    if(target) target = DestroyPixelWand(target);
	    MagickWandTerminus();
	}


       更多的C程序调用imagemagick API方法的例子,可以参考这个网站http://members.shaw.ca/el.supremo/MagickWand/


       最后,说句闲话。在网上看到过一个问题,是问cairo和ImageMagick这两个图像库,使用哪个更好。一个大牛最终总结:

Use Cairo if you need to do scalable vector graphics.

Use ImageMagick if you are ouputting to bitmap or raster formats.

       实际中比较了一下,cairo绘图的效果确实是比imagemagick要好。这个就看实际项目需要吧。

    

     



Logo

更多推荐