| JezUK Ltd - The Coffee Grounds - June 2006 |
| << May 2006 | July 2006 >> |
At the start of the week, we had a bathroom and, seperately, a loo. Now we have neither, just a big space where they used to.
Oh, and dust. Lots and lots and lots of dust. It's on every surface, in every crack and crevice. It swirls around your feet as you walk, and is forming dunes along the hall.
Gah.
As I've described before, the .NET framework provides lots of support for drawing lines and circles and polygons, but stinks the place up rather badly when you want plot a lot of pixels. Using the single-pixel bitmap technique, I found that plotting a not-unreasonable 150,000 pixels took over 5 seconds, which left me, having to draw six or eight such images, with a rendering time of up to 30 or 40 seconds. That's bad.
If you dig around a bit the stuff you need to draw bitmaps at good speed (ie, quickly enough that you don't bother getting the stopwatch out) is all there, it's just not really talked up anyway. The reason for that is that it's frightfully un-.NETty, flirting as it does with raw memory access, undocumented behaviour and all that kind of stuff.
First of all, you need a bitmap
Bitmap bmp = new Bitmap(width, height);
which we then lock
BitmapData bd = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
The rectangle doesn't have to cover the whole bitmap, so you can just select part of it if you want to. The LockBits documentation threatens to throw an exception if the PixelFormat is wrong, without describing which values might be right. Format24bppRgb worked for me.
The BitmapData object, bd, now has information we need. Most crucial is bd.Stride. The width you specified in the call to LockBits may not be the width of the actual area locked, as it will have been aligned on a word boundary (possibly depending on the pixel format, I think). The value of bd.Stride is, therefore, not necessarily equal to width. Armed with the height and bd.Stride we can allocate a linear array of bytes onto which we will actually do our drawing.
int bufferLength = bd.Stride * height;
byte[] buffer = new byte[bufferLength];
The start of the buffer corresponds to origin (0,0), and you just map your points into it
for(int x = 0; x < whatever; ++x)
for(int y = 0; y < something; ++y)
{
Color colour = data[x][y];
or whereever your data comes from
int index = (y * bd.Stride) + (x * 3);
We do x*3 here, because we specified 24bpp, so 3 bytes per pixel. Unfortunately we just have to know this, this value isn't available at runtime. Notice also that bd.Stride is given in bytes, not pixels.
buffer[index] = colour.B;
buffer[index+1] = colour.G;
buffer[index+2] = colour.R;
}
Note the order the colour bytes are set, blue is low, and that we need to use the Stride value to index into the buffer. Almost there now.
So, buffer is full of our data which we need to shove back into our bitmap
System.Runtime.InteropServices.Marshal.Copy(buffer, 0, bd.Scan0, bufferLength);
bitmap.UnlockBits(bd);
If you've made any mistakes, particularly in calculating the buffer size, you'll get a runtime exception from one or other of these calls.
That's it - the Bitmap can be drawn using DrawImage, DrawImageUnscaled or DrawImageUnscaledAndClipped.
Very little of this seems to be documented properly. I found out the byte order by trial and error, for example. If you try another pixel format, you'll have to do some similiar experimentation. To my mind, this looks like a lot of fiddly-faff and there are all kinds of questions I'd like to ask whoever designed this (like why do I need to lock the bitmap in memory but then allocate my own seperate buffer?), but it works and it's quick.
Nipped into the city centre yesterday to try and score a few comics. Arriving well before the advertised closing time, I nonetheless found the place locked up. My annoyance was compounded when I realised it was probably something to do with this stupid football malarkey.
Strolled out to the city centre with chums Pete and Tom, and Tom's chum Dan to refresh my Bob Mould man-crush. He played more or less the same set as at Bristol in January, but the gig had quite a different feel. The crowd was smaller but warmer which was good (also older, greyer and balder). The lighting was quite bright though, which meant that not only could we see Bob, he could see us. He closes his eyes a lot as he plays. When he opens them it's with this slightly crazed stare, and it's a little unnerving when his gaze falls on you. Worth it though. He'll be back with a band next year. I'll be there.
There are probably only three people in the world even remotely interested in this, but here's the picture anyway.

OK, maybe interested is too strong a word. That's a little .NET form, written in C#, running XQuery over an Astoria database using Saxon.NET. Astoria documents are wrapped in System.Xml compatible classes, demand loading child nodes so you only load the bits you use. The fn:doc XQuery function understand eclipse URIs in addition to the normal file and http varieties. The fn:collectin XQuery function takes a cabinet name and hands back all the docs that cabinet contains. It's all taken a bit less than a day.
On the one hand I feel like a programming rockstar, but on the other, well, you know, a bit silly. Maybe if it impresses the right people, they'll pay me to finish it off.
Wish I hadn't now.
I'll go back to me tea. [added 30th Jun 2006]
<doc>
<p>
<ftr>footer 1</ftr>
</p>
<p>
<ftr>footer 2</ftr>
</p>
</doc>
| XPath | Expected | Arabica behaviour |
|---|---|---|
| //ftr | Select both ftr elements | Correct |
| //ftr[1] | Select both ftr elements | Wrong - selects nothing |
| //ftr[2] | Select nothing | Correct - but for the wrong reasons |
| XPath Expression | Expected | Arabica behaviour |
| (//ftr)[1] | Select first ftr element | Correct |
| (//ftr)[2] | Select second ftr element | Correct |
Just finished reading a section of JPod in which one programmer, Kaitlin, lists the what she terms the microautisms of her cubicle-collegues. Came away wondering if I have some degree of auditory hyperacuity (don't really like the sounds of other people eating, often think people talk too loudly, have been known to wander the house at night trying to track down a buzzing noise that turned out to be the fridge or to turn off a dripping tap at far end of the house), face blindness (difficulty in reading people particularly strangers, but perhaps everyone has that), or whether I lack emotional reciprocity (often finish conversations aware that the other person has asked all the questions, misinterpret small talk pleasantries as genuine enquiries, that kind of thing). Probably I'm just a socially inept neurotypical acting like a hypochondriac with a medical encyclopedia.
This morning, I dropped the Bean off at his dance rehearsal. As I arrived back home, Hal saw me from the bedroom window and ran out on to the landing to shout hello down the stairs. "Hi Hal!" I replied, "what are you doing?" I was slightly startled when he replied "Standing at the top of the stairs."
Chum Ken popped round today to pick up some extra 2000ADs I'd unearthed during the move. He brought his son Ben and some more early 80s vintage comics fanzines with him. He took Ben away again, but he left the mags. They really are top. From 1982, we have BEM 35 featuring an enormous Pat Mills interview, a terrific Nemesis and Torquemada cover by Kev O'Neill, a further feature on Nemesis with Mills scripts and O'Neill pencils and inks and six page sci-fi story written and pencilled by our Lord Eddie Campbell. Also from 82 is Lew Stringer's Fantasy Express 4 with more O'Neill and huge great interview with Joe Colquhoun. We just don't do fanzine's like this anymore. I should round up a few of today's thrusting young zine publishers, take the zines and smack them all around the head with them until they get the message. More seriously, I'm starting to think I should scan this stuff, or at least bits of it. They're comics folk history, and if we don't preserve it, it'll just get lost.
Am enjoying JPod very much. It's not huge in the way of plot, but it's snappy and cynical and the programmer jokes are almost all accurate. It's also written in very short chunks, so it's ideal for the multi-tasking IT professional. Although Natalie completely failed to notice, the novel immediately preceding JPod as my evening time reading was Miss Wyoming, also by Douglas Coupland. I read the opening couple of chapters several years ago the morning following my chum John's stag do, nursing a significant hangover, sitting on the lavvy at about 8:30 in the morning. When I eventually picked up a copy, I recalled them almost completely. Is that a recommendation?
| << May 2006 | July 2006 >> |