在Mac上用Preview、Keynote、ImageMagick和FreeSWITCH进行图像处理
现在处理图片的软件这么多,你可能奇怪为什么需要用到FreeSWITCH处理图像。
是的,最流行也是最标准的图像处理工具当然是PhotoShop,PhotoShop如此流行,以至于它的缩写PS都成了图像处理的代名词。但是,PhotoShop唯一的缺点就是太贵,这些钱对于设计人员来说当然是值得花的,但对于广大程序员来说,它是个低频应用,可能一年中也用不了几次,就不合算。有时候实在需要,我也是使用GIMP凑合着用。GIMP是开源的,也能用,但说实话用起来确实不如PhotoShop顺手。
当然,作为一名程序员,希望寻找另外的工具的动机就是,是否有比较轻量级的工具,是否能自动批量处理等。
好了,言归正传,说说我为什么选了这么多工具来处理图像。
请听题:我的需求是,将我写的毛笔字底色处理成透明的,将黑色替换成需要的颜色,做在书的封面上。原始图像如下图。
当然这么折腾是有原因的,主要的原因是基本上所有好看的适合做封面的字体都是有版权的。
为了能在书中比较好的排版,在生成这幅图像时就使用了以下步骤和工具:
使用iPhone拍照,然后通过AirDrop传到Mac上,选中需要的文字,按⌘+K(或选菜单Tools --> Crop),保存或导出到PNG,就准备好了上面的图像。
查看图像的分辨率,这里用到了ImageMagick:
identify wenji-1.png
wenji.png PNG 4032x1682 4032x1682+0+0 8-bit sRGB 5.11007MiB 0.000u 0:00.000
当然图像的分辨率比较高,我们根据需要降一下分辨率,以避免占用不必要的空间:
convert wenji.png -resize 400x200 wenji-1.png
其中identity
和convert
都是ImageMagick里工具,后者可以改变图像的大小,生成一幅新的图像。『宽x高
』是目标图像的大小,它默认会保持图像的比例,即如果原始图像比例与目标比例不一致的情况下,实际尺寸可能会比指定的值小,如:
identify wenji-1.png
wenji-1.png PNG 400x167 400x167+0+0 8-bit sRGB 77381B 0.000u 0:00.000
接下来用以下命令就可以将底色变成透明的:
convert wenji-1.png -fuzz 40% -transparent white wenji-2.png
或
convert wenji-1.png -alpha set -channel RGBA -fuzz 20% -fill none +profile "*" +opaque "rgb(255,0,0)" wenji-2.png
下一步,尝试把文字变成红色的:
convert wenji-2.png -alpha set -channel RGBA -fuzz 50% -fill red -draw "color 135,99 replace" wenji-3.png
找到文字上的一个点(方法有很多,我使用的是在Preview中打开图像,然后用矩形选择框从左上角选取区域,在移动鼠标的过程中就可以看到当前坐标,在此我们找到的点是(135,99)),然后以此为中心选取范围为50%
的相似区域,替换成红色。图像如下。
但这样不完美:1)层次感没有了,2)太过粗糙。
虽然通过小心的调整参数可以做的好一点,但是还是达不到要求。
首先,ImageMagic在“抠图”(将底色变透明)时,由于背景明暗相差太大,需要很多次处理才能做得更好,但太多次数处理图像又会使图像质量变差,另外,我也不知道如何用ImageMagick处理颜色的层次。我们需要找新的工具。
完成这项任务的最好的工具当然是Keynote了。将原始图像插入Keynote,选右侧红色方框标的Instant Alpha按钮,然后用鼠标选中一个点,按下鼠标拖动就可以将相似的区域变为透明。超级好用。图中显示的是『文』字中间6%
的情况。可以在不同的区域重复多次以便得到完美的效果。
处理完毕后,再复制图像,回到Preview中,新建一幅图像,内存中的内容将自动粘贴到图像中,保存为PNG就好了(记着保存时要选中(Alpha)以保证图像中有透明通道)。由于底色已经完全透明,我们可以看到复制后的图像已经比以前变小了。
identify wenji-5.png
wenji-5.png PNG 256x143 256x143+0+0 8-bit sRGB 26574B 0.000u 0:00.000
下面的任务是要进行颜色替换,为此,我使用FreeSWITCH的库libfreeswitch
写了一个程序,先看效果。
./c wenji-5.png wenji-6.png
上代码。非常简单,连空行只有21行。
首先,第一行引入switch.h
头文件。程序从main
函数开始。在第5行,读入待处理的文件(命令行的第一个参数),在内容中存储的格式是ARGB
,即具有Alpha通道,以保存图像的透明信息。
1 #include <switch.h>
2
3 int main(int argc, char **argv)
4 {
5 switch_image_t *img = switch_img_read_png(argv[1], SWITCH_IMG_FMT_ARGB);
6 switch_assert(img);
7
8 int i, j;
9
第10行,对图像从上到下逐行扫描(其中d_h
为图像高度)。第11行,对当前行的每一个像素进行扫描。第12行,依次取每一个像素的颜色值。
其中img->planes[0]
为图像的起始地址,img->stride[0]
为图像的宽度(此处与img->d_w
相等)在ARGB格式的图像中,每个色彩分量占一个字节,取值范围为0~255
,所以一个像素占4个字节。switch_rgb_color_t
是一个颜色结构体,占4个字节。
10 for(j = 0; j < img->d_h; j++) {
11 for(i = 0; i < img->d_w; i++) {
12 switch_rgb_color_t c = *(switch_rgb_color_t *)(img->planes[0] + j * img->stride[0] + i * 4);
13
取得当前像素的颜色后,第14行将红色分量变为最大值255
,即最红,其它分量不变。第15行将颜色写回图像内存。
14 c.r = 255;
15 *(switch_rgb_color_t *)(img->planes[0] + j * img->stride[0] + i * 4) = c;
16 }
17 }
处理结束后,第19行将图像保存到新的文件(命令行上的第二个参数),并于第20行释放内存。
19 switch_img_write_png(img, argv[2]);
20 switch_img_free(&img);
21 }
程序很简单(简单起见没加太多的错误处理语句),用以下命令编译,生成可执行文件c
:
gcc -o c -I/usr/local/freeswitch/include/freeswitch -L/usr/local/freeswitch/lib -lfreeswitch c.c
不错,至此墨色浓淡,层次感都保存较好啦。还不错吧?
不过,这里还有一点点小问题。那就是《文集》的封面是黄色的,那么墨色越淡就应该越接近于黄色,而不是白色。当然这也难不住我们,我们知道,黄 = 红+绿
,所以,只需要将蓝色分量去掉就可以了。在第14行后面加入『c.b = 0;
』就将白色变成了黄色。当然,完全去掉蓝色分量会使那个像素变暗,所以,我们把其中一部分加回到绿色分量上,代码片断如下:
14 int g = c.g + c.b / 2;
15 c.r = 255;
16 c.g = g > 255 ? 255 : g;
17 c.b = 0;
加上黄色的底色看看,最终效果看起来还不错吧?
convert wenji-7.png -fuzz 25% -fill none -background yellow -flatten wenji-8.png
没有一个工具是完美的,但工程师总能找到合适的工具解决相应的问题。在看到此文之前,你是不是以为Preview只能用于看图,FreeSWITCH只能用于打电话呢?
本文分享自 FreeSWITCH中文社区 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!