« | » Main « | »

Maybe this represents a new low in manager/engineer relations. Maybe it's a new high in Matt's creative energy, which I know isn't going into his blog! In either case, it's a cool picture he did of me:

Me as Darth Nedibat

May the Farce be with you!

I needed a transparent PNG image of some text to overlay text on an image. My first try looked OK, but the edges of the text seemed to be the wrong color. After some finagling, I came up with PIL code that did the right thing.

Here was the first code I used:

import Image, ImageFont, ImageDraw

fontfile = r"C:\WINDOWS\Fonts\arialbd.ttf"

words = [
    ((10, 10), "Red", "#ff0000", 30),
    ((10, 50), "Green", "#00ff00", 30),
    ((10, 90), "Blue", "#0000ff", 30),
    ((10, 130), "White", "#ffffff", 30),
    ((10, 170), "Black", "#000000", 30),
    ]

# A fully transparent image to work on.
im = Image.new("RGBA", (120, 210), (0,0,0,0))
dr = ImageDraw.Draw(im)

for pos, text, color, size in words:
    
    font = ImageFont.truetype(fontfile, size)
    dr.text(pos, text, font=font, fill=color)

im.save("badtranstext.png", "PNG")

Here's the image it produces: (If you are viewing this in IE6, you won't see the transparency)

Red, Green, Blue, with black halosRed, Green, Blue, with black halosRed, Green, Blue, with black halos

You can see that the edges of the letters are grimy. The white text should not be visible at all against the white background, but you can see the edges.

This is because when PIL draws a partially-transparent pixel at the edge of a letter, it uses the partial coverage of the shape to blend the background and foreground pixels. If the background were fully opaque, this would be the right thing to do, but with a fully transparent background like we are using, this gives the wrong color. We specified the background as fully transparent black, so for a pixel half-covered with white, PIL computes a color of half-transparent gray. It should be half-transparent white, so that the final image will be able to blend properly with any color underneath it.

Look at it another way: if I specify the background as completely transparent (alpha of 0), then it shouldn't matter what color I provide for the RGB channels. I should get the same final result if I specify (0,0,0,0) or (255,255,255,0): the background is completely transparent, it has no color at all, those values are merely placeholders. But PIL will use the color channels to assign color to the edges of the type, so the placeholder "background color" will bleed into the result.

To get the proper result, I draw each string onto a separate gray channel, then add those gray pixels into an accumulated alpha channel. Then I use the gray text to compute full-color pixels for any pixels with even a slight trace of the text on it. When combined, the alpha channel will dilute down the color of the edge pixels down to give the proper appearance.

import Image, ImageFont, ImageDraw, ImageChops

fontfile = r"C:\WINDOWS\Fonts\arialbd.ttf"

words = [
    ((10, 10), "Red", "#ff0000", 30),
    ((10, 50), "Green", "#00ff00", 30),
    ((10, 90), "Blue", "#0000ff", 30),
    ((10, 130), "White", "#ffffff", 30),
    ((10, 170), "Black", "#000000", 30),
    ]

# A fully transparent image to work on, and a separate alpha channel.
im = Image.new("RGB", (120, 210), (0,0,0))
alpha = Image.new("L", im.size, "black")

for pos, text, color, size in words:
    
    # Make a grayscale image of the font, white on black.
    imtext = Image.new("L", im.size, 0)
    drtext = ImageDraw.Draw(imtext)
    font = ImageFont.truetype(fontfile, size)
    drtext.text(pos, text, font=font, fill="white")
        
    # Add the white text to our collected alpha channel. Gray pixels around
    # the edge of the text will eventually become partially transparent
    # pixels in the alpha channel.
    alpha = ImageChops.lighter(alpha, imtext)
    
    # Make a solid color, and add it to the color layer on every pixel
    # that has even a little bit of alpha showing.
    solidcolor = Image.new("RGBA", im.size, color)
    immask = Image.eval(imtext, lambda p: 255 * (int(p != 0)))
    im = Image.composite(solidcolor, im, immask)

# These two save()s are just to get demo images of the process.
im.save("transcolor.png", "PNG")
alpha.save("transalpha.png", "PNG")

# Add the alpha channel to the image, and save it out.
im.putalpha(alpha)
im.save("transtext.png", "PNG")

This is more work, but gives the correct results. Here's the alpha channel, the color channels, and the final result:

The alpha channelThe color channelThe final result

And the result on various backgrounds:

The good transparent textThe good transparent textThe good transparent text

At the last Python meetup, the presenter was going to talk about a concept (let's call it the XYZ pattern), and he wanted to make sure everyone understood the concept before he did. He did it in a common way, by saying,

Does anyone here not know what XYZ is?

This is the wrong way to do it.

When you ask a question like this of your audience, you get an uncomfortable pause. Your listeners now have to gauge their own knowledge:

  • The ones who have no idea what XYZ is will wonder if they'll look stupid for raising their hand.
  • The ones who have a vague idea will wonder if they need to know more, or if they can skate by.
  • Half the ones who are confident that they know what XYZ is actually have it a little wrong, but won't realize that they have a different conception than the speaker intended.

The talk will stop for a moment while people decide what to do. If someone asks for an explanation, the presenter will spend a little time explaining it. If no one does, the presenter might actually explain it a little bit anyway, because he was prepared to. Momentum has been lost and people feel awkward.

The better way to do this is to say,

As I'm sure I don't have to remind you, the XYZ pattern is a common way to mumble the frabbitz in systems with more than three quuxers. It's good because it separates the concerns about sculpting and shading.

In less time than it took to poll and embarrass the audience, you've:

  • Complimented your listeners about already knowing what XYZ is.
  • Defined XYZ, so those that didn't know now do.
  • Explained your view of XYZ, so that even those that did know it now have your take on it as a common starting point for the rest of the talk.

Chandler, the uber-PIM project from the Open Source Applications Foundation, has had a major life event. Many people are calling it the end of the project, and it may well be. People are still working on it, but the funding is cut, and the future is very very unclear.

This is too bad, it was an ambitious and idealistic project, perhaps too much so. I don't really know what was going on over there. I haven't read Dreaming in Code, I don't read the mailing lists, I haven't even looked at their software in years.

Remarkably, Carlos Perez blames it on Python. His piece is really something, because he starts by admitting that he suspected from the beginning that Python wasn't up to the task, and now he's pretty sure his suspicions have been confirmed. Except that he doesn't do any analysis of what actually went wrong at Chandler. He repeats his biases against dynamic languages, and concludes that they are to blame. He comes to this conclusion even as he points out how strange it is that Python is only used in the client, and the server is Java!

The consensus seems to be, and it seems right, that the problems with Chandler were:

  • Organization: too many heavy-hitters heading in their own directions. See the previous point about Python at the client and Java at the server.
  • Lack of focused target: replacing people's email infrastructure, while at the same time re-thinking how those activities are accomplished is a huge challenge.

Carlos' viewpoint will probably perservere. Chandler was in some ways seen as a poster child for Python, and its demise I'm sure will cause at least a minor meme along the lines of, "We can't use Python, look what happened to Chandler." This is too bad. I think the choice of language matters to a project, but not nearly as much as we techies often think. So many other things matter a great deal more.

Carlos points to Eclipse as an example of what can be accomplished with Java. Eclipse is an amazing achievement, but it isn't Java that did it. There's a huge amount of effort that goes into the focus and support that makes Eclipse what it is. As an example, have you ever read their release notes? These are amazing! No project in the history of the world has had such thorough, helpful, and well-crafted release notes. That's got nothing to do with Java, and everything to do with the care and work that the Eclipse organization puts into producing and supporting their software.

So here's to Chandler, a (nearly) departed friend. I hope that it continues in some meaningful form. Here's to good craftsmen (and their kibbitzers) not blaming their tools. Here's to using your language of choice as just one tool in your tool set. And here's to seeing your projects for what they are: a collection of people trying hard to achieve difficult goals the best they can.

tagged: , » 18 reactions

Simon Willison and Natalie Downe have launched Django People, a socialish site for discovering users of the Django web framework. It's heavily geography-based, which makes a nice counterpoint to the existing virtual community, where who knows where people live?

It's a very nicely done site, with a strong, clean look and smooth interactions. One odd point for US users: the per-state pages (Massachusetts, for example) feature state flags. I've lived in Boston for 22 years, and I could not have told you what the Massachusetts state flag looked like!

Small dedicated sites like this are great for their focus on one particular clumping factor, in this case, people who use Django. But I wonder about their future. How many of these niche networks can I be a part of? What will happen as the people in it morph due to changing skill sets, interests, and so on? In these days of Facebook and their exploding catalog of third party applications, what's the role for bespoke niche networks like Django People?

I've written up a page cataloging all the software tools I use for various tasks: Software I use.

tagged: , » 3 reactions

ha.ckers points to a proof-of-concept for printing unexpected pages when visiting a malicious web site. It didn't work for me. It relies on network printers listening on well-known IP aliases and ports (such as "myprinter:9100"). Mine doesn't seem to use that name, and I didn't see in the control panel where to configure the name it will use.

It's always fascinating to see the unexpected consequences of the systems we build...

When I recently re-built this site, some pages moved. For example, long-ish blog posts used to get a separate page with a name based on a time stamp, but now all blog posts have their own page with a slugged URL, so those old numeric URLs are obsolete.

Rather than abandon those URLs, though, I wanted to make sure that inbound links to my site weren't broken. To do this, I created a bunch of redirects. As I'm sure I don't need to explain, a redirect is when a web server returns not an HTML page, but a pointer to another URL that the browser should automatically load instead. The HTTP status code returned with the redirect indicates more about why the redirect is happening. In my case, I want a 301: Moved Permanently.

To implement the redirects, I used two technologies: Apache's mod_rewrite module, and PHP.

» read more of: Redirects... (18 paragraphs)

After all of this, what have we got?

  • I've avoided breaking inbound links. As I was working on this redesign, I went back through some old notes of ideas to try, and about half the interesting URLs I tried were broken. I was sad.
  • My URLs are more canonical. This helps with search engines and link aggregators, to make sure I don't get two entries when one will do.
tagged: , , » 12 reactions

This is an impressive traffic jam in a small place. It's a great illustration of the term "deadlock". Even the least technical person can take a look at this insanity and see that everyone is stuck (click to see more):

a crazy traffic jam

According to the reddit comments, this is in São Paulo, Brazil.

tagged:   /   via: Reddit» 7 reactions

I've been listening to podcasts of Fresh Air, the NPR interview show. I was struck by the intro blurb that precedes every podcast:

This is Terry Gross, the host of Fresh Air. You're listening to our podcast. Our program would not exist without our listeners who support their local public radio stations, so we want to start by saying, "Thanks."

How classy is that? These days there is so much content going online digitally, and so many people wringing their hands about how they will get paid, and who has the rights to use what, and how to track it and how to punish those that break the rules. The music industry treats their customers like criminals, DVDs always start with stern warnings and FBI logos. Fresh Air could have taken a similar confrontational stance.

Instead, they assumed the best, treated their listeners with respect, yet still got the message across that they have a responsibility to help support the endeavor. It's true that NPR is in a different position than record labels, but not that different. There's something to be said for entering a relationship with your customer where you focus on the good that could have happened rather than the bad.

I've made some changes to this site. In some ways, they are only small changes, but under the hood, they are quite large.

» read more of: Permalinks, Gravatars and Django... (8 paragraphs)

Everything should be working just as before, but there may be some hiccups. If you see anything amiss, please let me know!

tagged: , » 29 reactions

As Weird Al often does, he perfectly spoofs Bob Dylan in this video, singing an entire song in palindromes.

And since I've directed you to a perhaps undesired YouTube video, I will also share with you Brent Simmons' astute observations about the mental processes of a YouTube patron.

tagged: , » 2 reactions

I have a Western Digital 250Gb Passport drive for backing up my Windows laptop. I figured I would just use cygwin rsync to move data between the two drives. When I mount the Passport as drive Q, I use a command like this:

rsync -az --progress . /cygdrive/q/bak

This faithfully copies all the data, and avoids copying stuff that hasn't changed, mostly. But some files are copied every time I run the command, even when they haven't been changed, and in fact, a diff program shows that the source and the backup copy are identical. I figure it's some Windows characteristic of the file that is throwing off rsync and making it think the file needs to be copied, but I can't figure out what. Some of the files have capital letters in the filename, but not all of the afflicted files do. I never set permissions on files, so I don't think that could be it (but I could be wrong).

Anyone have any experience with this?

Jeff Atwood skewers developers for being distracted by the latest tools. He's right. As technology lovers, we believe the latest technology will be far better (faster, easier, produce better results) than older technology.

Illustrator Bob Staake has made some videos showing how he creates his drawings, like many artists do these days. Unlike most artists, though, Bob uses Photoshop 3.0. Yes, 3.0, the same program he's been using since 1995. His input device? A mouse. This proves the adage that a good craftsman never blames his tools, and that it's not about what you have, it's about how you use it.

tagged: , ,   /   via: Drawn!» 2 reactions

The music industry (a misnomer: I really mean the blood-sucking short-sighted middlemen who have nothing directly to do with music) is apparently so clueless that they now are suing people for buying CDs and then ripping them for their personal use: Download Uproar: Record Industry Goes After Personal Use.

The RIAA's legal crusade against its customers is a classic example of an old media company clinging to a business model that has collapsed. Four years of a failed strategy has only "created a whole market of people who specifically look to buy independent goods so as not to deal with the big record companies," Beckerman says. "Every problem they're trying to solve is worse now than when they started."

Amen.

Update: turns out the Washington Post got it wrong, and the suit is about copying .mp3's to file sharing services. So this is not an example of whole new levels of cluelessness, just the same old levels of cluelessness.

tagged:   /   via: JOHO the Blog» 4 reactions

Iowa

Saturday 5 January 2008

I'm already sick of the whole thing. This process has been going on for a year already, and we still have 10 months more to go. Iowa's caucuses are being treated like a coronation. The Boston Globe had an inch-high headline announcing the winners, in a contest that produces 1% of the delegates, and has been wrong half the time. There have been 13 interesting Iowa caucuses (where more than one candidate was running) since 1972, and they have chosen the eventual nominee only 7 times. In three cases, it was the third-place finisher who was nominated.

Why do we give in to this craving for quantitative results? I want to hear a news outlet pledge to never report poll numbers. I would listen to them exclusively!

The whole focus on early primaries seems completely out of whack to me, where a small handful of small states get to make big choices for everyone. And the circus this year of each state moving their primaries up in a game of political chicken underscores the inanity of the system. I'd like a state other than New Hampshire to pass a state law requiring their primary to be the earliest, then let the Supreme Court figure out what to do with two mutually contradictory state laws.

I'm intrigued by Giuliani simply sitting out the early states, focusing on ones which provide more delegates. I'm for anything that breaks us out of the Barbie and Ken two-party rut we've gotten ourselves into.

tagged: » 6 reactions

As a fan of geometry, and especially stellations (see the logo in the upper left), I have mixed feelings about the 3D star light fixtures I often see. They are pleasing, but they are not based on any real math. They look like stellations, but they are not. Susan will point out a star lamp to me, and is used to me replying, "It's nice, but it isn't right."

Hans Schepker to the rescue! His mathematically correct lighting page demonstrates that you can make light fixtures based on strict mathematical forms. He has some really interesting compound form lamps. The three cubes compound is especially nice:

Beautiful three cube compound lamp

You may recognize the shape from the top of one of the towers in Escher's Waterfall.

tagged: » 2 reactions

PyCon?

Wednesday 2 January 2008

I was wondering if I had any calendar conflicts with PyCon this year, so I went to the PyCon 2008 Chicago page to figure out exactly when it was. I was surprised to see my face at the top of the page! The photo (and the one of the Django coding session) are by my co-worker Dave St. Germain. I remember some talk about using those photos on a flyer for the conference, but hadn't heard they'd be on the site. I guess I have to go now...

tagged: » react

To whomever this reaches, an electronic version of our holiday card:

The five of us, on the beach

Peace
Stay warm.

I took the picture last August at sunset on First Encounter Beach in Eastham on Cape Cod, specifically trying to get a shot that would work for a card. I used a Nikon ML-L3 remote so I could take lots of pictures without getting up to click the self-timer shutter. You can see I have the remote in my hand, clicking it with my thumb.

My brother Patrick did the photo editing needed to make the original shot usable:

The original shot, with people walking around

Happy 2008, everybody!

« | » Main « | »