Friday, March 25, 2005

Serif fonts.

I have developed an aversion to serif fonts such as Times New Roman. For preference I use Verdana which has subtle differences from Arial or MS Sans-Serif and which I think is a far more readable typeface.
Arial is a slightly cramped typeface that has connotations of a serif font particularly because of the lower case "a" which I find to stand out almost as though it was purposefully created in a different style from the rest of the font.
Verdana has an open style which is far better proportioned and the "a" fits right in with the rest of the font as if it belongs.
Times is a very cramped typeface, this paragraph is the same point size as the Verdana above but you must agree is not nearly as easy on the eye. It reminds me of cheap paperback books and seems to lower the quality of the text. I know it's almost a 'traditional' font but I do wish that it wasn't the default for everything.
Georgia is Verdana's serif cousin and is more open and readable so as a compromise I tend to use it when serif fonts are required.
For me, Verdana is the queen of fonts.

Unsafe isn't

I've noticed that many programmers seem to have an irrational fear of the "unsafe" keyword in C#. It's almost as though they are afraid that if they use it in their code then program will turn into a Frankenstiens Monster and leap opon them in their sleep.
Unsafe refers only to the fact that the code might reference unmanaged and hence non type-safe code. Not that one is taking a calculated risk by using it.
Personally, I only use unsafe where the highest performance is required and I don't want anything to intervene between my code and the bytes it's working on. In most of my puplicly available examples these days I use the Marshal class because it enables me to create code in C# which is readily translated to VB. This is of course just my lazy nature and not a fear of the evil that may befall me if I use that dreaded keyword.

Monday, March 14, 2005

Turn the world on it's head!

Today I have had a bit of a shock. In response to a newsgroup posting I decided to update my article on generating 1 bit per pixel images from 24bpp colour. The original article used a mixture of Bitmap.GetPixel and LockBits to determine the pixel brightness and write the single bit pixel to the image array and I had decided to convert this to a LockBits solution on both sides of the equation for the sake of completeness.
I re-wrote the C# code so that instead of using unsafe pointers it used the Marshal class to read and write the bytes. This made the code identical in function to the VB conversion. After testing the C# code I did a quick conversion to VB and wran the two applications on the same image.
I noticed that the VB application seemed to be faster so I added a diagnostic routing to time how long the central part of the loop, the one that actually does the conversion, took. To make sure the code had a good chunk of data to work with I used an image that was 4000*3200 pixels.
To my great surprise the VB code is consistently faster by over three seconds with the C# doing the loop in around eight seconds and the VB running the functionally identical code in only five.
I have seen instances before where the VB compiler was demonstrably better at generating code than the C# one but have never seen it so clearly shown to be superior at simple tasks than the C# compiler.
The timed code is shown in both C# and VB here:
C#
DateTime dt=DateTime.Now;

//scan through the pixels Y by X
int x,y;
for(y=0;y {
for(x=0;x {
//generate the address of the colour pixel
int index=y*bmdo.Stride+(x*4);
//check its brightness
if(Color.FromArgb(Marshal.ReadByte(bmdo.Scan0,index+2),
Marshal.ReadByte(bmdo.Scan0,index+1),
Marshal.ReadByte(bmdo.Scan0,index)).GetBrightness()>0.5f)
this.SetIndexedPixel(x,y,bmdn,true); //set it if its bright.
}
}

//tidy up
bm.UnlockBits(bmdn);
img.UnlockBits(bmdo);

//show the time taken to do the conversion
TimeSpan ts=dt-DateTime.Now;
VB
'for diagnostics
Dim dt As DateTime = DateTime.Now

'scan through the pixels Y by X
Dim y As Integer
For y = 0 To img.Height - 1
Dim x As Integer
For x = 0 To img.Width - 1
'generate the address of the colour pixel
Dim index As Integer = y * bmdo.Stride + x * 4
'check its brightness
If Color.FromArgb(Marshal.ReadByte(bmdo.Scan0, index + 2), Marshal.ReadByte(bmdo.Scan0, index + 1), Marshal.ReadByte(bmdo.Scan0, index)).GetBrightness() > 0.5F Then
Me.SetIndexedPixel(x, y, bmdn, True) 'set it if its bright.
End If
Next x
Next y
'tidy up
bm.UnlockBits(bmdn)
img.UnlockBits(bmdo)

'show the time taken to do the conversion
Dim ts As TimeSpan = dt.Subtract(DateTime.Now)
I'll have to compare the IL for the two compiled sections to see where the C# compiler fails to get that extra few ergs.

Friday, March 11, 2005

Does there have to be a reason?

I am a proponent of wordy explanations but there are some times when a simple and definitive answer should be taken at face value and not questioned.

Children often ask "Daddy, what would happen if I were to poke my tongue in the electrical outlet?" wherupon daddy will reply "You'll die a horrible and painful death son". This should be enough of an answer and should be heeded by all small boys.

When a programmer asks "Can I store the Graphics object?" the answer is "No!". This is one of those definitive answers that is usually questioned but which always ends up being "No!" however many times or in however many different ways it's asked.

Just to recap....

Do not store the Graphics object. Do not store it in a local variable, a static variable, a shared variable, an object, a structure or a database. Do not put it in an envelope and post it to your aunt, do not draw a picture of it, do not photocopy it, do not have Monet make a painting of it.
Do not put it in your pocket for later, do not hash encode it and e-mail it to the CIA, do not put it on a Post-it note and stick it to your screen, do not grind it into powder and sniff it up your nose with the other stuff you just had. In short....

DO NOT STORE THE GRAPHICS OBJECT!