Photoshop中的Multiply Blend Mode

Multiply是PS中常用的一种混合方式,中文版称为“正片叠底”模式。
说起来非常简单,就是颜色分量相乘。但实际上简单的相乘并没有考虑到alpha channel。
如果两个图层都是RGBA四个通道,Multiply的算法还得加入alpha。

为了搞清楚这个问题,我琢磨了好几个小时。最后从颜色含义入手,配合一些测试结果,终于推出了PS的混合公式:

OutAlpha = A1 + A2 - A1*A2
OutColor = (1.0 - (1.0 - C1)*A1) * (1.0 - (1.0 - C2)*A2)

可以看出这个公式对于A1和A2是对称的,所以被混合的两个图层没有前后之分。

推理过程如下:Multiply混合可以看作是两张幻灯片叠在一起,因为变得更厚所以透过的颜色变少,从而达到减色效果。在这里颜色分量Color是光可以透过的程度,1.0即表示该颜色分量全部可以透过。1.0-Color表示被吸收掉的部分。在PS的混合算法中,Alpha用来调节吸收程度。因为Alpha经常用于表示透明度,1.0表示完全不透明,即吸收程度为100%。

结合以上两个定义:

(1.0 - Color) * Alpha // 表示被吸收的颜色
1.0 - (1.0 - Color) * Alpha // 表示最终透过的颜色

把两个最终透过的颜色相乘,即得到我们需要的最终减色结果。

在忽略Alpha只有RGB混合的情况下,Alpha都取1.0,则公式可以化简为:

OutAlpha = 1.0
OutColor = C1 * C2

结果为颜色分量直接相乘,也就是到处都可以找到的对Multiply的算法的描述。

以下是c#版的实现……

static byte Clamp(int result)
{
    if (result < 0)
        return (byte)0;
    
    return result > 255 ? (byte)255 : (byte)result;
}

static byte MultiplyColor(int lhs, int rhs, int lhsAlpha, int rhsAlpha)
{
    if (lhsAlpha == 0)
        return Clamp(rhs);
    else if (rhsAlpha == 0)
        return Clamp(lhs);

    int lhsMultiply = (255 - (255 - lhs) * lhsAlpha / 255);
    int rhsMultiply = (255 - (255 - rhs) * rhsAlpha / 255);
    int result = rhsMultiply * lhsMultiply / 255;
    return Clamp(result);
}

// same as Photoshop multiply blend mode
static public void Multiply(Bitmap lhs, Bitmap rhs, Rectangle roi)
{
    BitmapData lhsData = SetImageToProcess(lhs, roi);
    BitmapData rhsData = SetImageToProcess(rhs, roi);

    int width = lhsData.Width;
    int height = lhsData.Height;
    int offset = lhsData.Stride;

    unsafe
    {
        byte* lhsPtr = (byte*)lhsData.Scan0;
        byte* rhsPtr = (byte*)rhsData.Scan0;

        for (int y = 0; y < height; ++y)
        {
            for (int x = 0; x < width * 4; x+=4)
            {
                int lhsAlpha = lhsPtr[x + 3];
                int rhsAlpha = rhsPtr[x + 3];

                // multiply color with alpha factor
                lhsPtr[x + 0] = MultiplyColor(lhsPtr[x + 0], rhsPtr[x + 0], lhsAlpha, rhsAlpha);
                lhsPtr[x + 1] = MultiplyColor(lhsPtr[x + 1], rhsPtr[x + 1], lhsAlpha, rhsAlpha);
                lhsPtr[x + 2] = MultiplyColor(lhsPtr[x + 2], rhsPtr[x + 2], lhsAlpha, rhsAlpha);

                // also blend the alpha channel
                int retAlpha = (lhsAlpha + rhsAlpha - lhsAlpha * rhsAlpha / 255);
                lhsPtr[x + 3] = Clamp(retAlpha);
            }
            lhsPtr += offset;
            rhsPtr += offset;
        }
    }
    lhs.UnlockBits(lhsData);
    rhs.UnlockBits(rhsData);
}

2014驾到

这里确实已经变成年签了,好久不登录连密码都忘记了。

2013很丰富,通了很多游戏,更新了战斗装备,所以关键字一大堆。

有ROSE,树莓派,DQ,DAO,巫师,星际2,炉石传说……

还有悲剧的丢包,棒极了的圣诞游,难忘的歌剧,以及超萌的小猫……

年中开始做AAA,却很快产生了厌倦,无论去留都不完美,十分鸡肋。

作为互联网难民,翻墙的代价还真不小啊……

对未来就不期待什么突破了,2014能完坑我就很满意啦。

在git中添加hg仓库

因为要改sdl的代码,又不想用hg,所以想找个类似remote svn一样的玩意儿。

放狗一搜结果发现还真有,作者felipec写了很详细的介绍:
http://felipec.wordpress.com/2012/11/13/git-remote-hg-bzr-2/

看起来是linux下的玩意儿,但作者没说在windows下怎么用。既然是个脚本,没理由不能在windows下跑。继续搜,找到了一个人在stack overflow上的发问,关于这玩意儿怎么安装的问题:

http://stackoverflow.com/questions/883452/git-interoperability-with-a-mercurial-repository

felipec很乐于推销自己的作品,此问题就是他回答的。可惜还是没说清楚怎么安装,所以评论里也有人喷他,’Simplicity. Ah… Magic!’

我只好先去他的github上看看代码:
https://github.com/felipec/git/blob/fc/master/contrib/remote-helpers/git-remote-hg.py

代码里似乎有windows的字样,也许最近更新过。好吧就假设windows可以直接用了,我下载了一份,把python27也装上,设置好PATH。

根据作者一贯的口气,只要把脚本也放到PATH中的路径下即可。我照做,然后执行:

git clone hg::http://<any-hg-url>

却报了个很奇怪的错:

fatal: git was built without support for
C:\Program (NO_PYTHON=YesPlease)

这个YesPlease的提示看起来很怨念的样子,我继续搜,果然也有人在问:
https://groups.google.com/forum/?fromgroups#!topic/msysgit/LpyViW97g0A

一看内容我就笑了,貌似是msysgit的人在喷这个felipec,说他不肯和msysgit合作。结果felipec跳出来反喷,说msysgit有意忽略他的作品。

总之他俩很欢乐的喷了半天,还是没说怎么安装……

我只好自力更生…… 先搜了一下文件名,在msysgit的安装目录git\libexec\git-core中居然发现了名为git-remote-hg的文件,内容就几行:

#!/bin/sh
echo >&2 "fatal: git was built without support for `basename $0` (NO_PYTHON=YesPlease)."
exit 128

我擦咧这不就是报错的地方么。我想了想,把git-remote-hg.py去掉扩展名,然后替换了这个文件。试了下git clone,这下有点进步了,脚本开始运行,报错说找不到mercurial模块。

好吧我确实忘记给python安装mercurial模块了。于是到hg的官网下载mercurial-2.6.tar.gz,然后尝试执行里面的setup.py:

python setup.py build

build居然报错:

error: Unable to find vcvarsall.bat

我一直以为mercurial是纯python的,原来还有c代码!可是我有装vs2012,vcvarsall.bat是用来配置vc编译环境的,按道理我是有的。

只好继续搜,翻过各种不靠谱的页面之后,找到了一篇详细的解释:
http://stackoverflow.com/questions/3047542/building-lxml-for-python-2-7-on-windows/5122521#5122521

简单的说就是python的windows版都是用vs2008编译的,所以它非要找vs2008的环境变量。如果换编译器来编译模块,可能工作不正常。

这个帖子建议是,去装个免费的vs2008 express吧!

看到这里我直接晕倒,开源社区的人对待windows用户真是不友好啊。何以解忧?唯有google!绕了一大圈后,我在mercurial官网看到了解决方案:
http://mercurial.selenic.com/wiki/WindowsInstall

原来只需要强制换用其他编译环境就好,譬如官网说可以用mingw来代替:

python setup.py build --force -c mingw32
python setup.py install --force --skip-build

嗯嗯,还是官网靠谱,于是乎mercurial的python package终于可以编译安装了。

接下来回到我的最初目的:

git clone hg::http://<any-hg-url>

顺利通过了!嗯嗯,终于可以开始干正事儿了……

简单记录一下

树莓派到手之后,参考网上的资料折腾了几天,都是很基本的东西。

1、SD卡

为了读写速度,专程购买了Kingston的32G Class10高速SD卡,标号SD10V/32G。

虽然官方列表http://elinux.org/RPi_SD_cards 信誓旦旦表示it works,但装好系统镜像之后boot报错。似乎是部分数据不可读,虽然能看到树莓派logo,也似乎开始加载内核,但很快就停滞,一直提示timeout。在网上搜了下,很多人抱怨这个卡没法用,推荐Sandisk的牌子,我手头没有不评价。更换成一张Kingston 8G Class4的卡之后终于可以启动系统镜像,还好新买的卡可以用在相机上,否则就浪费了……

后来找到个很老的Kingston 512m TF卡,加了套子之后也可以正常的使用在树莓派上。因为容量问题,只能加载其他小号系统镜像,因为官方镜像要求2G空间。

2、系统镜像

我安装的是2013-02-09-wheezy-raspbian.zip,Raspbian “wheezy”,应该是个Debian的RPi移植版。

关于如何安装镜像,如何设置,参考了这篇文章:《树莓派Raspberry Pi上手报告

不过我的显示器无法直接全屏显示1080p的画面,手动修改了config.txt中的显示模式才得以全屏。树莓派的官方系统镜像为2G,刷写之后,多于2G的部分没有分区,最好在第一次设置的时候扩展到全盘。

系统设置界面的选项,选定之后项目会立即生效,这有点出乎我的意料。实际上设置界面并不是简单的修改配置文件,而是要运行某些配置程序。

3、系统更新

注意更新之前需要连接网线。刚开始玩的时候我也不知道为啥需要更新,但很多文章都建议首先做如下步骤,我就照做了:

sudo apt-get update

sudo apt-get upgrade

后来才知道这是更新Raspbian的软件包和系统程序。最新的镜像里可能不如网上当前的版本新,更新一下聊胜于无。

4、固件更新

树莓派的固件是放在SD卡的第一个分区上的,这个分区是FAT分区,直接在windows也可以查看。

此分区上保存的几个文件,是在启动时被GPU/CPU自动加载的。因为树莓派没有bios,它的GPU首先会读取SD卡文件,靠文件名或config.txt中的配置,以固定顺序加载几个文件,然后再唤醒CPU。

具体可以参考这里的描述:

http://elinux.org/RPi_Software

http://kariddi.blogspot.sg/2012/08/raspberry-pi-bare-metal-part-1-boot.html

总之,更新固件很简单,拷贝文件到SD卡即可。最新的固件托管在github上,而且有人制作了脚本来自动更新固件。

https://github.com/Hexxeh/rpi-update

参考网站说明即可,相当于自动下载文件然后拷贝到第一个分区/boot/

5、软件安装

最方便的方法是接网线,然后通过网络安装各种软件。基本上两种方法:

a) 用sudu apt-get install命令安装软件包。很方便,不过需要有网络。

b) 用git来安装,很多软件并没有放到系统的软件包列表中,需要用git直接拿到编译好的版本或源码。

已经记不太清楚最初安装了些什么,基本上属于用到啥装啥。但gcc编译器,git,以及chrome都是一定要装的,系统自带的浏览器比较弱……

安装chrome,仍然可以参考雷锋网那篇文章。装好编译器,源码就可以直接在树莓派上编了。在pc上编比较麻烦,得配置交叉编译环境,因为树莓派是arm芯片。

6、总结

到此为止,一个可用的系统差不多就弄好了。不过这样只是换了个地方玩linux,如果想研究linux可以继续折腾。因为树莓派比我想象的慢,在上面玩linux不如在虚拟机上玩。

但我对树莓派本身比较感兴趣,打算抛开linux来折腾它。但接下来先记录一下安装ruby,SDL,web服务,以及我那坑爹的Linksys AE3000无线网卡的安装过程。

To be continued…

树莓派上瘾中

终于从家里把Raspberry Pi带来了,红色PCB果然好看很多。显然装个linux是不能满足我的好奇心的,接下来就好好折腾一下吧~

不过当初是因为缺货才从家里买,结果现在也不需要了,于是又搞了个绿色的版本。一红一绿,试试看pi to pi的开发模式……

以前一直对操作系统没有兴趣,最近兴趣大增,是该研究研究了。

蛇年到

过了这么多个除夕之后,已经木有当年那种兴奋的感觉了……不过今年例外,头一次这样过年,还挺新鲜的。

值得一提的是,从去年11.3开始沉迷Dota2,至今已在它身上消耗了近250个小时。难道要打破我在MH3中创下的300小时的记录么?

说起来Farcry3确实是个好游戏,是唯一能让我停下Dota2还能将之穿掉的玩意儿,MGS4都不能做到这一点。还有可怜的Borderlands也终于被搞定了,遗憾的是二代很贵且担心机器带不动,从长计议吧……

蛇年要到了,嘶嘶嘶~~

数字游戏商店

【Steam】

优点就不多说了,缺点是DRM太讨厌,必须装steam才可以玩。但毕竟是个大平台,在线玩可以拿成就,还可以和朋友联机。而且切换成离线模式后就不用担心网络的问题了。首选的在线商店:)

【Humble Bundle】

如果碰到想玩的indie,这里还是很不错的。但大部分都是过气的游戏,优点是便宜和无DRM。

【Origin】

令人讨厌的平台,有Steam就足够了为啥EA要搞自己的呢?导致很多游戏在Steam上不再销售。建议只考虑在Steam上找不到的游戏,因为它拥有Steam的全部缺点且没有任何额外优点。

【GameStop】

意外发现的一个商店,也有类似Steam的客户端,好处是有很多老游戏,且DRM没有那么严格,不装它的平台也可以用。但缺点是安装游戏还得靠它的平台。

【GoG】

这也是个销售廉价的无DRM的游戏的网站,很多超级老的游戏,大部分游戏都不超过6美元。

【Amazon】

亚马逊也开始销售数字版游戏了,优点是没有讨厌的平台,买了之后就可以下安装包和序列号。如果遇到活动,还是可以买到便宜的游戏的。

【PSN】

尝试过港服,UI做的太难用了,而且折扣少。还是在美服上注册Plus会员比较划算,有很多折扣以及免费送出的游戏。

【BigFish】

这个平台基本上就是流氓软件,装完之后带一堆奇怪的插件。DRM很严格,必须开着它的app才可以用,问题是这个app没有任何功能。建议不要试,类似天朝的各种小游戏平台估计也差不多德性,离的越远越好……

豆知识

上周末修自己的电脑,获得了一些非常无聊的心得体会,为了防止帕金森所以记在这里。

1、安装VS2011的时候,电脑过热非正常关机,然后安装中断且重新安装不能。

其实是因为自己在和同事联机打《left 4 dead 2》,这个游戏不错哦,推荐一下!好吧,扯远了,我本以为是msi安装包又傲娇了,自己把自己锁住了。经过一番折腾,手动卸载了几十个VS2011残留组件之后,仍然无法安装。后来换装VS2010,结果.NET Framework 4仍然安装不上。报错0xC8000247,显示某个安装包无法pause windows update。搜索之后发现这篇帖子:http://answers.microsoft.com/en-us/windows/forum/windows_7-windows_update/error-code-0xc8000247-cant-install-updates/198166df-9549-e011-8dfc-68b599b31bf5

里面有个哥们儿提到Intel Rapid Storage Technology Driver的旧版本会导致windows update在西数的硬盘上无法正常工作。我的三星本本确实装过“英特尔快速储存技术”这个驱动,虽然不知道这驱动是干什么的但买来就装着。然后我去下了最新版的驱动,更新后再次开始VS2010的安装,一切正常。

所以问题的根本原因并不是突然关机,而是因为前几天我换了一块西数的硬盘……WTF!!!

2、储存在“我的图片”文件夹中的图片,在拷贝到别的文件夹之后,文件内容被修改。

这一点让我非常恼怒,因为这个修改是随机的,有时候发生有时候没事。导致的结果就是我的游戏截图文件不能按照时间排序,所有的图片都乱套了。经过一番探索,结论是图片被某种神秘程序加了一段内容,因为不仅是日期,实际连文件大小都发生了变化。

经过搜索发现有人称是Windows Media Center这个服务搞的鬼,为了管理图片什么的。所以不要把文件储存在My Pictures目录中,避免WMC来接管你的图片。http://www.sevenforums.com/music-pictures-video/218692-windows-7-keeps-changing-my-pictures-filesize-modified-date.html

然后我又很想恢复文件到修改前的状态,所以研究了下添加的东西。其实WMC给文件添加了一些metadata,包括jpg和png都会被添加日期之类的信息。使用.NET Framework的BitmapDecoder可以读取或者修改这些metadata,也就是所谓的RDF (Resource Description Framework)信息。我很蛋疼的写了一小段程序,发现win7会给jpg添加”/xmp/MicrosoftPhoto:DateAcquired”字段的信息,会给png添加”/tExt/{str=Creation Time}”字段的信息。真是令人讨厌设计啊,我又默默的诅咒了一位微软的PM。

嗯嗯,就是这么两件事情,果然是数据洁癖么= =b