PythonMagick库使用心得
Posted darknight
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PythonMagick库使用心得相关的知识,希望对你有一定的参考价值。
PythonMagick是imagemagick的python版本
实际上他是magick++的封装。函数,参数和magick++是一样的
参考文档:https://imagemagick.org/Magick++/tutorial/Magick++_tutorial.pdf
下面是一些摸索下来的心得,提供给需要的人,少走弯路
1 颜色空间转换
接到一个任务,批量生成荣誉证书,要求根据设计稿,生成图片:格式:JPG,PPI:300,颜色模式:CMYK,提供的素材也是这样的格式
首先想到的是用PIL库来操作,毕竟在python上面基本是标准库了
因为证书上还需要添加证件照,证件照只有RGB模式的,所以需要将图片从RGB转到CMYK
PIL下面就是一个convert就搞定了
lena =Image.open("lena.jpg") lena_CMYK =lena.convert("CMYK")
但是就是颜色不对,转过来的图片变色了(如下图,右边是美工提供的设计稿,左边是通过PIL转换的cmyk),这样的色差是难以接受的
查了下原因,PIL的转换,操作比较简单,k值直接是0,这样颜色必然是不准的
模式“RGB”转换为模式“CMYK”以后,图像从三通道变成了四通道,其C、M、Y三个通道的数值是通过之前的公式计算得到,K通道被直接赋值为0。 C = 255 - R M = 255 - G Y = 255 - B K = 0
通过查询,得知需要导入icc文件才能得到ps的转换效果,查询了PIL,没有找到导入的选项(这里可能是本人水平有限,没有找到,如果有的话,希望能回复下,研究下看看)
查询下来,找到了一个工具imagemagick,是一个图片处理的工具包,这个工具包可以将图片转换颜色,按照提供的icc进行转换
命令行操作很简单
convert -profile "sRGB.icm" RGB.jpg -profile "CMYK.icc" CMYK.jpg
这样就完成了颜色的转换,和PS下转换的效果是一样的
然后发现这个工具包有python下面的库,http://www.lfd.uci.edu/~gohlke/pythonlibs/#pythonmagick
2.7版本的不知道为啥,总是装不好,换了3.7的就ok了
安装好以后查看支持的函数,dir(PythonMagick),可以看到如下函数,具体的函数帮助可以输入help()来查看
[\'Blob\', \'Color\', \'ColorspaceType\', \'CompositeOperator\', \'CompressionType\', \'Coordinate\', \'DecorationType\', \'DrawableAffine\', \'DrawableAlpha\', \'DrawableArc\', \'DrawableBezier\', \'DrawableCircle\', \'DrawableClipPath\', \'DrawableColor\', \'DrawableCompositeImage\', \'DrawableEllipse\', \'DrawableFillColor\', \'DrawableFillOpacity\', \'DrawableFillRule\', \'DrawableFont\', \'DrawableGravity\', \'DrawableLine\', \'DrawableMiterLimit\', \'DrawablePath\', \'DrawablePoint\', \'DrawablePointSize\', \'DrawablePolygon\', \'DrawablePolyline\', \'DrawablePopClipPath\', \'DrawablePopGraphicContext\', \'DrawablePopPattern\', \'DrawablePushClipPath\', \'DrawablePushGraphicContext\', \'DrawablePushPattern\', \'DrawableRectangle\', \'DrawableRotation\', \'DrawableRoundRectangle\', \'DrawableScaling\', \'DrawableSkewX\', \'DrawableSkewY\', \'DrawableStrokeAntialias\', \'DrawableStrokeColor\', \'DrawableStrokeDashArray\', \'DrawableStrokeDashOffset\', \'DrawableStrokeLineCap\', \'DrawableStrokeLineJoin\', \'DrawableStrokeOpacity\', \'DrawableStrokeWidth\', \'DrawableText\', \'DrawableTextAntialias\', \'DrawableTextDecoration\', \'DrawableTextUnderColor\', \'DrawableTranslation\', \'DrawableViewbox\', \'Exception\', \'FilterType\', \'Geometry\', \'GravityType\', \'Image\', \'PathArcAbs\', \'PathArcArgs\', \'PathArcRel\', \'PathClosePath\', \'PathCurvetoAbs\', \'PathCurvetoArgs\', \'PathCurvetoRel\', \'PathLinetoAbs\', \'PathLinetoHorizontalAbs\', \'PathLinetoHorizontalRel\', \'PathLinetoRel\', \'PathLinetoVerticalAbs\', \'PathLinetoVerticalRel\', \'PathMovetoAbs\', \'PathMovetoRel\', \'PathQuadraticCurvetoAbs\', \'PathQuadraticCurvetoArgs\', \'PathQuadraticCurvetoRel\', \'PathSmoothCurvetoAbs\', \'PathSmoothCurvetoRel\', \'PathSmoothQuadraticCurvetoAbs\', \'PathSmoothQuadraticCurvetoRel\', \'Pixels\', \'TypeMetric\', \'VPath\', \'_PythonMagick\', \'__builtins__\', \'__cached__\', \'__doc__\', \'__file__\', \'__loader__\', \'__name__\', \'__package__\', \'__path__\', \'__spec__\']
这个是PythonMagick.Image下的函数
[\'__class__\', \'__delattr__\', \'__dict__\', \'__dir__\', \'__doc__\', \'__eq__\', \'__format__\', \'__ge__\', \'__getattribute__\', \'__gt__\', \'__hash__\', \'__init__\', \'__init_subclass__\', \'__instance_size__\', \'__le__\', \'__lt__\', \'__module__\', \'__ne__\', \'__new__\', \'__reduce__\', \'__reduce_ex__\', \'__repr__\', \'__setattr__\', \'__sizeof__\', \'__str__\', \'__subclasshook__\', \'__weakref__\', \'adaptiveThreshold\', \'addNoise\', \'adjoin\', \'affineTransform\', \'alpha\', \'animationDelay\', \'animationIterations\', \'annotate\', \'attribute\', \'backgroundColor\', \'backgroundTexture\', \'baseColumns\', \'baseFilename\', \'baseRows\', \'blur\', \'border\', \'borderColor\', \'boundingBox\', \'boxColor\', \'channel\', \'channelDepth\', \'charcoal\', \'chop\', \'chromaBluePrimary\', \'chromaGreenPrimary\', \'chromaRedPrimary\', \'chromaWhitePoint\', \'classType\', \'colorFuzz\', \'colorMap\', \'colorMapSize\', \'colorSpace\', \'colorize\', \'columns\', \'comment\', \'compare\', \'compose\', \'composite\', \'compressType\', \'contrast\', \'convolve\', \'crop\', \'cycleColormap\', \'debug\', \'defineSet\', \'defineValue\', \'density\', \'depth\', \'despeckle\', \'directory\', \'display\', \'draw\', \'edge\', \'emboss\', \'endian\', \'enhance\', \'equalize\', \'erase\', \'fileName\', \'fileSize\', \'fillColor\', \'fillPattern\', \'fillRule\', \'filterType\', \'flip\', \'floodFillAlpha\', \'floodFillColor\', \'floodFillTexture\', \'flop\', \'font\', \'fontPointsize\', \'fontTypeMetrics\', \'format\', \'frame\', \'gamma\', \'gaussianBlur\', \'geometry\', \'gifDisposeMethod\', \'iccColorProfile\', \'implode\', \'interlaceType\', \'iptcProfile\', \'isValid\', \'label\', \'magick\', \'magnify\', \'map\', \'matteColor\', \'meanErrorPerPixel\', \'medianFilter\', \'minify\', \'modifyImage\', \'modulate\', \'modulusDepth\', \'monochrome\', \'montageGeometry\', \'negate\', \'normalize\', \'normalizedMaxError\', \'normalizedMeanError\', \'oilPaint\', \'opaque\', \'page\', \'ping\', \'pixelColor\', \'process\', \'profile\', \'quality\', \'quantize\', \'quantizeColorSpace\', \'quantizeColors\', \'quantizeDither\', \'quantizeTreeDepth\', \'raise\', \'read\', \'readPixels\', \'reduceNoise\', \'renderingIntent\', \'resize\', \'resolutionUnits\', \'roll\', \'rotate\', \'rows\', \'sample\', \'scale\', \'scene\', \'segment\', \'shade\', \'sharpen\', \'shave\', \'shear\', \'signature\', \'size\', \'solarize\', \'spread\', \'statistics\', \'stegano\', \'stereo\', \'strip\', \'strokeAntiAlias\', \'strokeColor\', \'strokeDashOffset\', \'strokeLineCap\', \'strokeLineJoin\', \'strokeMiterLimit\', \'strokePattern\', \'strokeWidth\', \'subImage\', \'subRange\', \'swirl\', \'syncPixels\', \'textEncoding\', \'texture\', \'threshold\', \'totalColors\', \'transformOrigin\', \'transformReset\', \'transformRotation\', \'transformScale\', \'transformSkewX\', \'transformSkewY\', \'transparent\', \'trim\', \'type\', \'unsharpmask\', \'verbose\', \'wave\', \'write\', \'writePixels\', \'x11Display\', \'xResolution\', \'yResolution\', \'zoom\']
=============================================================================================
上面都是介绍,下面才是正文
=============================================================================================
经过测试,加载icc文件使用的是\'iccColorProfile\'这个函数,如下是内置的帮助,可以看到,有2中用法,
1,传入blob类型参数,就可以设置icc文件
2,不传入参数,可以返回一个blob类型,意思是获取这个图片当前的icc文件
blob是内存中的二进制文件类型
Help on built-in function iccColorProfile: iccColorProfile(...) iccColorProfile( (Image)arg1, (Blob)arg2) -> None : C++ signature : void iccColorProfile(class Magick::Image {lvalue},class Magick::Blob) iccColorProfile( (Image)arg1) -> Blob : C++ signature : class Magick::Blob iccColorProfile(class Magick::Image {lvalue})
官方的文档提供了blob类型的设置
Blob::Blob(); Blob::Blob(void* data, unsigned int size); // explicitly specifies a memory area to be // associated with the new Blob object Blob::operator=(const Blob& blob); // Examples of using Blobs in conjuction with Images Blob my_blob; // create a blob Image my_image("my_image.gif"); // create an image form a GIF image file my_image.magick("JPEG"); // set JPEG output format my_image.write(&my_blob); // encode \'my_image\' in JPEG format, // and store the encoded image in my_blob Image image_from_blob(my_blob); // create an image from the JPEG blob // (use the Blob-based Image constructor) image_from_blob.magick("BMP"); // set the image format to bitmap image_from_blob.write("image_from_blob.bmp"); // save the image on disk in BMP format
使用image打开一个文件,然后写入到一个新的Blob类型即可,这边写了一个函数,调用即可得到一个Blob类型的实例,内容是相应的icc文件
#获取对应颜色空间的blob(例如cmyk,rgb) def get_color_blob(file_name): color = PythonMagick.Blob() im = PythonMagick.Image(file_name) im.write(color,"icc") return color
cmyk = get_color_blob("CMYK.icc") temp = PythonMagick.Image("rgb.jpg") temp.iccColorProfile(cmyk) temp.write("cmyk.jpg")
这样就能完成从rgb到cmyk的转换了,经测试,转换效果完美,和ps转换出来是一摸一样的
2 PPI设置
使用pythonmagick的话无需设置PPI,原始是300PPI,保存下来就是300PPI,但是使用PIL打开300PPI的图片,进行操作,然后保存,就会变成蜜汁72PPI(这个在印刷制品上是
不行的,印刷出来会模糊),pythonmagick完美的避开了这个坑
3 图片缩放
img = PythonMagick.Image("test.jpg") #不保持比例 img.sample(\'298x412!\') #保持比例 img.sample(\'298x412\')
4 图片覆盖
有时候需要把一个透明的PNG覆盖到底图的某个位置,比如说一个印章
back_img = PythonMagick.Image("back.jpg") logo_img = PythonMagick.Image("logo.png") #此操作会出现logo的底图是黑色的 back_img.composite(logo_img,x,y) #使用over模式,具体可以查看magick++的文档,对应查找pythonmagick下面的函数,其他模式类似 back_img.composite(logo_img,x,y,PythonMagick.CompositeOperator.OverCompositeOp)
5 文字书写
系统提供DrawableFont,Image.annotate来在图片上书写字体
这里介绍使用ttf字体进行书写,并且使用奇葩的方法来实现粗体,字间距
Image.annotate查看系统的说明如下
Help on built-in function annotate: annotate(...) annotate( (Image)arg1, (str)arg2, (Geometry)arg3) -> None : C++ signature : void annotate(class Magick::Image {lvalue},class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class Magick::Geometry) annotate( (Image)arg1, (str)arg2, (Geometry)arg3, (GravityType)arg4) -> None : C++ signature : void annotate(class Magick::Image {lvalue},class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class Magick::Geometry,enum MagickCore::GravityType) annotate( (Image)arg1, (str)arg2, (Geometry)arg3, (GravityType)arg4, (float)arg5) -> None : C++ signature : void annotate(class Magick::Image {lvalue},class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class Magick::Geometry,enum MagickCore::GravityType,double) annotate( (Image)arg1, (str)arg2, (GravityType)arg3) -> None : C++ signature : void annotate(class Magick::Image {lvalue},class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,enum MagickCore::GravityType)
测试代码如下,注意:如果图片是cmyk模式,请先转换成rgb再书写文字,最后再保存cmyk,否则会变色
#打开底图 img = PythonMagick.Image("test.jpg") #设置ttf字体 img.font("W3.TTF") #设置字体大小 img.fontPointsize(60) #设置颜色 img.fillColor(PythonMagick.Color("#ff00ff")) #书写字体(100,100是xy坐标) img.annotate("你好",PythonMagick.Geometry("+100+100")) #保存 img.write("000.jpg")
测试写字(下图是使用了奇葩方法实现的粗体,因为找不到粗体的选项)
之前使用PIL写字可以加粗,但是他写出来的字体比ps里面粗,而且无法调整粗的程度
这里就自己写了个加粗方法,原理很简单,写5次文字,
首先x,y坐标写一次
然后x-1,y写一次,x+1,y写一次,x,y-1写一次,x,y+1写一次
就是上下左右各偏一个像素写一遍,这样写出来的文字和ps里面的粗体可以说能达到99%的相似度
可以看出,书写出来的文字还是有一些差异的,不过这样的效果完全是OK的
#书写粗体字(默认间隔) def img_text_bold(img,font_name,size,text,postion): img.font(font_name) img.fontPointsize(size) #img.annotate(text,PythonMagick.Geometry("+%s+%s"%(postion[0],postion[1]))) img.annotate(text,PythonMagick.Geometry("+%s+%s"%(postion[0]+1,postion[1]))) img.annotate(text,PythonMagick.Geometry("+%s+%s"%(postion[0]-1,postion[1]))) img.annotate(text,PythonMagick.Geometry("+%s+%s"%(postion[0],postion[1]+1))) img.annotate(text,PythonMagick.Geometry("+%s+%s"%(postion[0],postion[1]-1)))
#书写粗体字(自定义间隔) def img_text_bold_space(img,font_name,size,space,text,postion): zz = 0 for i in text: postion_new = [postion[0]+int(round(zz*space)),postion[1]] img_text_bold(img,font_name,size,i,postion_new) zz = zz + 1
因为找不到行间距这个参数,所以只能写一个奇葩的方法来实现字间距,实现原理就是一个个字写,写完一个字偏移一定的像素,如此来达到设置字间距的效果
如下效果
通过这一系列奇葩实现,可以达到设计稿的95%相似度,这样就完成了任务
6 图片对象引用
back_img = PythonMagick.Image("back.png") temp1 = back_img #对temp1进行各种操作,比如写字,剪裁,反转等 temp1.xxx() temp1.xxx() temp1.write("001.png") temp2 = back_img #对temp2进行各种操作,比如写字,剪裁,反转等 temp2.xxx() temp2.xxx() temp2.write("002.png")
上面的引用是不行的,temp2保存下来会带有temp1的操作效果,他这里 = 操作只是引用,不是复制
正确的做法是先新建一个Blob对象,把底图放在里面,然后temp去读取这个Blob对象来获得一个图片对象
#获取一个图片的Blob对象 def get_img_blob(file_name): last = file_name.split(".")[-1] img = PythonMagick.Image(file_name) blob = PythonMagick.Blob() img.write(blob,last) return blob
back_img_blob = get_img_blob("back.png") temp1 = PythonMagick.Image(back_img_blob) #对temp1进行各种操作,比如写字,剪裁,反转等 temp1.xxx() temp1.xxx() temp1.write("001.png") temp2 = PythonMagick.Image(back_img_blob) #对temp2进行各种操作,比如写字,剪裁,反转等 temp2.xxx() temp2.xxx() temp2.write("002.png")
以上是关于PythonMagick库使用心得的主要内容,如果未能解决你的问题,请参考以下文章