LinuxGem
此处为老的 LinuxGem,新版 LinuxGem 请移步 www.linuxgem.org

DIY 一个用于生成桌面墙纸的“网络相机”

galeki posted @ 2009年4月25日 03:52 in 编程技巧与工具 with tags python ImageMagick montage , 5653 阅读

Ben 写了一个 python 脚本——WebCam,区区百十行代码,实现了从网络或本地目录抓取多幅图片并随机拼合到一起,所生成的图片可以作为漂亮的桌面墙纸。这个脚本程序虽然不是非常智能,但是它可以作为一个 python 编程示例供初学者借鉴。您也可以尝试做一个 Lua 或 Ruby 版本

这个脚本的全部代码如下:

#! /usr/bin/env python
 
# Copyright 2009 by Benjamin Fogle
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
import sys
import os
import os.path
import urllib2
import tempfile
import math
 
# Constants.  Change these to customize the script
# In ksh: CONFIG_FILE=$HOME/lectures/examples/LEC-05/webcam_config
CONFIG_FILE=os.getenv('HOME') + '/.webcam_config'
TARGET=os.getenv('HOME') + '/Pictures/Wallpapers/webcam.jpg'
SCREEN_X = 1024
SCREEN_Y = 768
 
def GetTiles(num_images):
    """Returns a tuple (N,M) representing the tile grid"""
    # This algorithm could be much improved
    tile = math.ceil(math.sqrt(N))
    return (tile, tile)
 
def GetImageSize(N, M):
    """Returns a the max size of each image based on the screen size
    and the tile grid"
""
    global SCREEN_X
    global SCREEN_Y
    ImgX = SCREEN_X / N
    ImgY = SCREEN_Y / M
    return (ImgX, ImgY)
 
def CopyFile(src_fp, dest_fp):
    """Copy a file intelligently"""
    data = src_fp.read(49152)   # Copy 48k at a time
    while data:
        dest_fp.write(data)
        data = src_fp.read(49152)
    # Note: shutils.copyfileobj does this too.
 
if len(sys.argv) != 1:
    print "Usage: %s" % (sys.argv[0])
    print
    print "Config file is located in %s" % CONFIG_FILE
    sys.exit(1)
 
# Make sure the config file is readable and that it is a regular file
# There is a better way to do this that we will learn later.
if not os.access(CONFIG_FILE, os.R_OK) or not os.path.isfile(CONFIG_FILE):
    print "Error: %s could not be opened!" % CONFIG_FILE
    sys.exit(2)
 
urls = []           # Url to download from.  Read from config file
captions = []       # Captions for each image. Read from config file
filenames = []      # Temporary file names
 
config_fp = open(CONFIG_FILE, 'r')
line = config_fp.readline()
N=0
while line:
    params = line.split(":::")
    urls.append(params[0].strip())
    captions.append(params[1].strip())
    line = config_fp.readline()
    N+=1
config_fp.close()
 
 
# Download each url.  This is how to iterate over mutliple lists at once
for url, caption in zip(urls, captions):
    url_fp = urllib2.urlopen(url)
    # The following two lines are the preffered way to open a temporary
    # file.
    fd, name = tempfile.mkstemp()
    img_fp = os.fdopen(fd, 'w')
    filenames.append(name)
    CopyFile(url_fp, img_fp)
    url_fp.close()
    img_fp.close()  # The data won't appear in img_fp until it's closed
    # Use the ImageMagick suite from the shell to add a caption
    os.system("convert '%s' -set comment '%s' '%s'" % \
              (name, caption, name))
 
# Figure out the parameters
tilex, tiley = GetTiles(N)
imgx, imgy = GetImageSize(tilex, tiley)
 
# Use ImageMagick again to assemble the wallpaper
cmd = "montage -geometry %dx%d \
               -tile %dx%d \
               -set caption '%%c' \
               -pointsize 32 \
               -size %dx%d \
               -texture plasma: \
               +polaroid \
               -background black "
% (imgx, imgy, tilex, tiley,
                       SCREEN_X, SCREEN_Y)
 
# Add each image file to the command string
for filename in filenames:
    cmd += '"%s" ' % filename
 
# Add the output file to the command string and execute
cmd += TARGET
os.system(cmd)
 
# Cleanup
for filename in filenames:
    os.unlink(filename)     # In ksh:  rm $filename

要运行该脚本,需要您的系统中已经安装 imagemagick(一般 GNU/Linux 会默认为您安装该软件包)。

首先将上述代码复制到 webcam 文件并保存;然后,为该文件的添加可执行权限:

$ chmod  +x  webcam

在使用该脚本之前,需要将所要获取图片的地址信息写入 .webcam_config 文件,例如:

$ echo "file:///home/garfileo/Winter.jpg ::: 冬天" >> $HOME/.webcam_config
$ echo "http://www.51766.com/bbs/photo/1127887493353.jpg ::: 昌平∙白虎涧" >> $HOME/.webcam_config
$ echo "http://tw.mjjq.com/pic/20070530/20070530043314558.jpg ::: 赤水" >> $HOME/.webcam_config
$ echo "file:///home/garfileo/MY-Moutain.jpg ::: 明月山" >> $HOME/.webcam_config

然后,只需要执行 webcam 脚本,便可以在 $HOME/Pictures/Wallpapers 目录(若无该目录,请自行创建)中生成合成图片。上面向 .webcam_config 文件写入的四幅图地址,第一幅与第四幅图位于我的本地目录,而其它两幅均来自网络。每幅图片的地址后面均尾随 ":::" 符号,它是用来间隔图片地址与图片标签名的。这些图片的合成效果如下:

按照上述步骤正确操作,最终可以得到合成图片。不过,如果图片标签名是中文的话,那么最终的合成图中每幅小图的标签应该是一串问号或乱码。这是因为 webcam 脚本是通过调用 imagemagick 图片处理工具箱中的 montage 程序实现图片合成的,如果在图片中使用了中文标签名,那么需要设定中文字体方能在合成图中正确显示中文。要解决这个问题,需要在 webcam 脚本中找到以下代码段:

...... ......

# Use ImageMagick again to assemble the wallpaper

cmd = "montage -geometry %dx%d \
               -tile %dx%d \
               -set caption '%%c' \
               -pointsize 32 \
               ...... ......

然后在其中添加字体设置代码:

...... ......

# Use ImageMagick again to assemble the wallpaper
cmd = "montage -geometry %dx%d \
               -font /usr/share/fonts/winfonts/msyh.ttf \
               -tile %dx%d \
               -set caption '%%c' \
               -pointsize 32 \
               ...... ......

这样,这个问题便解决了。

Willing 说:
2009年5月01日 19:21

很喜欢这个网站,每次我要找主题都会来这里看一看,呵呵

daf3707 说:
2009年5月09日 21:25

不错

另外,论坛风格还是这样好

guowei 说:
2009年7月11日 21:11

报错:

Traceback (most recent call last):
File "./webcam", line 85, in <module>
url_fp = urllib2.urlopen(url)
File "/usr/lib/python2.6/urllib2.py", line 124, in urlopen
return _opener.open(url, data, timeout)
File "/usr/lib/python2.6/urllib2.py", line 383, in open
response = self._open(req, data)
File "/usr/lib/python2.6/urllib2.py", line 401, in _open
'_open', req)
File "/usr/lib/python2.6/urllib2.py", line 361, in _call_chain
result = func(*args)
File "/usr/lib/python2.6/urllib2.py", line 1226, in file_open
return self.open_local_file(req)
File "/usr/lib/python2.6/urllib2.py", line 1262, in open_local_file
raise URLError(msg)
urllib2.URLError: <urlopen error [Errno 2] No such file or directory: '/home/garfileo/Winter.jpg'>

LiYanrui 说:
2009年7月11日 22:39

@guowei: 对配置文件根据你的情况进行自适应修改


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter