做网站推广哪些,如何做网站解析,网站建设上海网站制作,解决方案网站2022-03-26 Sat
对ImageMagick的number_channels及PixelChannelMap结构体中的channel和offset成员的理解
这个标题有点长#xff0c;可能文章的内容也有点长#xff0c;但是思路越来越清晰。先来看PixelChannelMap的结构体定义#xff1a;
typedef struct _Pixel…2022-03-26 Sat
对ImageMagick的number_channels及PixelChannelMap结构体中的channel和offset成员的理解
这个标题有点长可能文章的内容也有点长但是思路越来越清晰。先来看PixelChannelMap的结构体定义
typedef struct _PixelChannelMap
{PixelChannelchannel;PixelTraittraits;ssize_toffset;
} PixelChannelMap;PixelChannelMap在ImageMagick的_Image结构体中对应成员channel_map
PixelChannelMap*channel_map;首先要说的是channel_map在逐个计算像素的过程中非常重要拿ImageMagick的resize.c:HorizontalFilter()函数为例
for (i0; i (ssize_t) GetPixelChannels(image); i)
{doublealpha,gamma,pixel;PixelChannelchannel;PixelTraitresize_traits,traits;ssize_tj;ssize_tk;channelGetPixelChannelChannel(image,i);traitsGetPixelChannelTraits(image,channel);resize_traitsGetPixelChannelTraits(resize_image,channel);if ((traits UndefinedPixelTrait) ||(resize_traits UndefinedPixelTrait))continue;if (((resize_traits CopyPixelTrait) ! 0) ||(GetPixelWriteMask(resize_image,q) (QuantumRange/2))){j(ssize_t) (MagickMin(MagickMax(bisect,(double) start),(double)stop-1.0)0.5);ky*(contribution[n-1].pixel-contribution[0].pixel1)(contribution[j-start].pixel-contribution[0].pixel);SetPixelChannel(resize_image,channel,p[k*GetPixelChannels(image)i],q);continue;}pixel0.0;if ((resize_traits BlendPixelTrait) 0){/*No alpha blending.*/for (j0; j n; j){ky*(contribution[n-1].pixel-contribution[0].pixel1)(contribution[j].pixel-contribution[0].pixel);alphacontribution[j].weight;pixelalpha*p[k*GetPixelChannels(image)i];}SetPixelChannel(resize_image,channel,ClampToQuantum(pixel),q);continue;}/*Alpha blending.*/gamma0.0;for (j0; j n; j){ky*(contribution[n-1].pixel-contribution[0].pixel1)(contribution[j].pixel-contribution[0].pixel);alphacontribution[j].weight*QuantumScale*GetPixelAlpha(image,pk*GetPixelChannels(image));pixelalpha*p[k*GetPixelChannels(image)i];gammaalpha;}gammaPerceptibleReciprocal(gamma);SetPixelChannel(resize_image,channel,ClampToQuantum(gamma*pixel),q);
}这个循环中的GetPixelChannels()函数就是返回number_channels的值
static inline size_t GetPixelChannels(const Image *magick_restrict image)
{return(image-number_channels);
}即处理每个像素的所有channel通过GetPixelChannelChannel()函数以通道的offset成员获得对应的channel
static inline PixelChannel GetPixelChannelChannel(const Image *magick_restrict image,const ssize_t offset)
{return(image-channel_map[offset].channel);
}返回的channel是PixelChannel类型这个定义在上面的文章中已经给出了
typedef enum
{UndefinedPixelChannel 0,RedPixelChannel 0,CyanPixelChannel 0,GrayPixelChannel 0,LPixelChannel 0,LabelPixelChannel 0,YPixelChannel 0,aPixelChannel 1,GreenPixelChannel 1,MagentaPixelChannel 1,CbPixelChannel 1,bPixelChannel 2,BluePixelChannel 2,YellowPixelChannel 2,CrPixelChannel 2,BlackPixelChannel 3,AlphaPixelChannel 4,IndexPixelChannel 5,ReadMaskPixelChannel 6,WriteMaskPixelChannel 7,MetaPixelChannel 8,CompositeMaskPixelChannel 9,IntensityPixelChannel MaxPixelChannels, /* ???? */CompositePixelChannel MaxPixelChannels, /* ???? */SyncPixelChannel MaxPixelChannels1 /* not a real channel */
} PixelChannel; /* must correspond to ChannelType */看定义我之前还在奇怪为什么enum类型指定了好多相同的0值1值现在终于明白了。即比如RGB和CMYK两种形式R和C都是第0个通道G和M都是第1个通道依次类推。CMYK中的K就是black在PixelChannel中对应的是BlackPixelChannel。
重点就是SetPixelChannel()这个函数
static inline void SetPixelChannel(const Image *magick_restrict image,const PixelChannel channel,const Quantum quantum,Quantum *magick_restrict pixel)
{if (image-channel_map[channel].traits ! UndefinedPixelTrait)pixel[image-channel_map[channel].offset]quantum;
}这里忽略理解traits最后一个参数pixel就是处理像素后的目标地址代码中的channel是通过循环i获取的offset是通过channel获取的最终计算出了pixel的真正地址然后将计算好的quantum赋值进去。
最后channel_map中的channel和offset是在哪里初始化的我对比了代码发现只在
static inline void SetPixelChannelAttributes(const Image *magick_restrict image,const PixelChannel channel,const PixelTrait traits,const ssize_t offset)
{if ((ssize_t) channel MaxPixelChannels)return;if (offset MaxPixelChannels)return;image-channel_map[offset].channelchannel;image-channel_map[channel].offsetoffset;image-channel_map[channel].traitstraits;
}而SetPixelChannelAttributes()只在InitializePixelChannelMap()函数中会被调用InitializePixelChannelMap()这个函数有点熟悉在之前了解number_channels的文章中做过了介绍这个函数内部计算并初始化了number_channels的值。
我对GraphicsMagick和ImageMagick进行了比较GraphicsMagick对ImageMagick进行了精简代码
for (y0; y (long) destination-rows; y){doubleweight;DoublePixelPacketpixel;longj;register longi;pixelzero;if ((destination-matte) || (destination-colorspace CMYKColorspace)){doubletransparency_coeff,normalize;normalize0.0;for (i0; i n; i){jy*(contribution[n-1].pixel-contribution[0].pixel1)(contribution[i].pixel-contribution[0].pixel);weightcontribution[i].weight;transparency_coeff weight * (1 - ((double) p[j].opacity/TransparentOpacity));pixel.redtransparency_coeff*p[j].red;pixel.greentransparency_coeff*p[j].green;pixel.bluetransparency_coeff*p[j].blue;pixel.opacityweight*p[j].opacity;normalize transparency_coeff;}normalize 1.0 / (AbsoluteValue(normalize) MagickEpsilon ? 1.0 : normalize);pixel.red * normalize;pixel.green * normalize;pixel.blue * normalize;q[y].redRoundDoubleToQuantum(pixel.red);q[y].greenRoundDoubleToQuantum(pixel.green);q[y].blueRoundDoubleToQuantum(pixel.blue);q[y].opacityRoundDoubleToQuantum(pixel.opacity);}else{for (i0; i n; i){j(long) (y*(contribution[n-1].pixel-contribution[0].pixel1)(contribution[i].pixel-contribution[0].pixel));weightcontribution[i].weight;pixel.redweight*p[j].red;pixel.greenweight*p[j].green;pixel.blueweight*p[j].blue;}q[y].redRoundDoubleToQuantum(pixel.red);q[y].greenRoundDoubleToQuantum(pixel.green);q[y].blueRoundDoubleToQuantum(pixel.blue);q[y].opacityOpaqueOpacity;}if ((indexes ! (IndexPacket *) NULL) (source_indexes ! (IndexPacket *) NULL)){iMin(Max((long) (center0.5),start),stop-1);jy*(contribution[n-1].pixel-contribution[0].pixel1)(contribution[i-start].pixel-contribution[0].pixel);indexes[y]source_indexes[j];}}从上面的代码可看出在GraphicsMagick中只处理了matte通道或CMYKColorsapce它们都是四通道的。但是看到代码中的indexes不知道这个在GraphicsMagick中的意义及是否在ImageMagick中有相关对应。
可以在GraphicsMagick中通过搜索indexes_valid来找到一些有用的信息
/*Indexes are valid if the image storage class is PseudoClass or thecolorspace is CMYK.
*/
cache_info-indexes_valid((image-storage_class PseudoClass) ||(image-colorspace CMYKColorspace));原来是这样这里的PseudoClass就是pseudocolor可以在wiki的Indexed color中找到介绍之所以叫做索引颜色是因为为了节省内存或磁盘空间颜色信息不是直接由图片的像素所携带而是存放在一个单独的颜色表中或者调色板中。
从上面贴出来的ImageMagick和GraphicsMagick的代码对比发现下面两段代码类似
// ImageMagick
if (((resize_traits CopyPixelTrait) ! 0) ||(GetPixelWriteMask(resize_image,q) (QuantumRange/2))){j(ssize_t) (MagickMin(MagickMax(bisect,(double) start),(double)stop-1.0)0.5);ky*(contribution[n-1].pixel-contribution[0].pixel1)(contribution[j-start].pixel-contribution[0].pixel);SetPixelChannel(resize_image,channel,p[k*GetPixelChannels(image)i],q);continue;}// GraphicsMagick
if ((indexes ! (IndexPacket *) NULL) (source_indexes ! (IndexPacket *) NULL)){iMin(Max((long) (center0.5),start),stop-1);jy*(contribution[n-1].pixel-contribution[0].pixel1)(contribution[i-start].pixel-contribution[0].pixel);indexes[y]source_indexes[j];}依然参考InitializePixelChannelMap()的代码结合刚刚知道的GraphicsMagick对于PseudoClass和CMYKColorspace时indexes有效在ImageMagick中则CopyPixelTrait对应IndexPixelChannel
if (image-colorspace CMYKColorspace)SetPixelChannelAttributes(image,BlackPixelChannel,trait,n);
if (image-alpha_trait ! UndefinedPixelTrait)SetPixelChannelAttributes(image,AlphaPixelChannel,CopyPixelTrait,n);
if (image-storage_class PseudoClass)SetPixelChannelAttributes(image,IndexPixelChannel,CopyPixelTrait,n);
if ((image-channels ReadMaskChannel) ! 0)SetPixelChannelAttributes(image,ReadMaskPixelChannel,CopyPixelTrait,n);
if ((image-channels WriteMaskChannel) ! 0)SetPixelChannelAttributes(image,WriteMaskPixelChannel,CopyPixelTrait,n);
if ((image-channels CompositeMaskChannel) ! 0)SetPixelChannelAttributes(image,CompositeMaskPixelChannel,CopyPixelTrait,n);不同的是ImageMagick中CMYKColorspace没有CopyPixelTrait特性。
小结一下以目前的开发状态将ImageMagick中的CopyPixelTrait与GraphicsMagick中的indexes对应起来。
又一个闪退问题
今天突然发现
[ysouynoarch ~]$ export MAGICK_OCL_DEVICEtrue
[ysouynoarch ~]$ gm display ~/temp/bg1a.jpg
Abort was called at 39 line in file:
/build/intel-compute-runtime/src/compute-runtime-22.11.22682/shared/source/built_ins/built_ins.cpp
gm display: abort due to signal 6 (SIGABRT) Abort...
Aborted (core dumped)
[ysouynoarch ~]$ clinfo
Abort was called at 39 line in file:
/build/intel-compute-runtime/src/compute-runtime-22.11.22682/shared/source/built_ins/built_ins.cpp
Aborted (core dumped)连clinfo都运行不了了它也同样闪退了看来肯定不是我代码的问题了。可能就是因为intel-compute-runtime的版本更新引起的。