&. |

A software developer’s musings on software development

ImageSizer

Warning: I wrote this blog in 2009. That is a long time ago, especially on the internet. My opinions may have changed since then. Technological progress may have made this information completely obsolete. Proceed with caution.

I wrote a program last week for resizing images so that they can fit onto a two-monitor desktop, and I figured I’d share with the world before heading to the beach. This program does more than just resize an image, though. It accounts for the gap between the two monitors, so that it looks much more like you are looking through the monitors. Most of this post will consist of an explanation of what exactly that means and why you’d want to do it.

Okay, for starters let’s say you have two monitors sitting side-by-side. In our example, these monitors each have a resolution of 304×228 pixels, giving a resolution of 608×228 for the entire desktop. Here is what that looks like:1

Blank two-monitor setup

Now, let’s say you want to use this photo of the Gizah pyramids by Ricardo Liberato, the #21 finalist for Wikimedia Commons Picture of the Year 2007, as your wallpaper. Here is what the photo looks like initially:

A great photo of the Gizah pyramids

There is a problem here, because that’s not the right proportion, so you’d want to crop out a portion of the image that is the right proportion. Here is a cropped portion that is the proper ratio and size (608×228):

The Gizah pyramids photo, resized to 608×228

Now, let’s use that image as our desktop wallpaper on our dual-monitor setup:

The Gizah pyramids stretched across a two-monitor setup

I don’t know about you, but I find this very aesthetically displeasing. Suddenly the pyramid is not shaped like a pyramid anymore! Your mind expects the image to continue through the space between the monitors, but it actually just picks up where it left off on the edge of the other screen. In fact, it kinda makes it look like there is a fourth, smaller pyramid, between the first and second one.

So here’s where my app comes in. We need to figure out how wide that gap is, in pixels. If you knew the dpi of your monitor, you could measure the gap in inches and calculate the number of pixels. But if you don’t know that, here’s how I measure it. Open up any kind of image editing app (Paint will do just fine). Place the window so that it straddles the gap between monitors. Draw a 45-degree line that spans the monitors. It is very important that the line be exactly 45 degrees (you can hold control or shift or something to fix the line to 45 degrees in most image editing apps). Now, hold something with a straight edge (say, a piece of paper) so that it lines up with the line on one monitor. Holding the straight edge there, click somewhere on the other monitor, where the line would be if it was accounting for the gap, and draw another 45-degree line starting from there. Now measure the vertical distance, in pixels, between the two lines. This will be equivalent to the horizontal distance, in pixels, between the two monitors. For our example, here is what that might look like:

Example of measuring gap between monitors

You can see the solid black line is “straight” if the gap is not accounted for. However, the dashed line shows how the line would behave if the gap was considered to have a width. The distance between the dashed line and the solid line on the right-hand monitor is 50 pixels, so that is the width of our gap. So now, let’s use my app:

java -jar ImageSizer.jar pyramids.jpg -monitorWidth 304 -height 228 -gap 50

This will generate pyramids.resized.png, which looks like this:

Gizah pyramids resized by tool, accounting for gap

When we use this image as our desktop wallpaper, we get an image that looks correct:

The Gizah pyramids stretched across a two-monitor setup, accounting for the gap between the monitors

If you’d like the program, you can download the source right here. But before you use it, here are a few things you should know:

  • You may get OutOfMemory exceptions on very large images. If this happens (thanks Peter), you can increase the Java heap size from the command line like this: java -Xmx256m -jar ImageSizer.jar .... If that still doesn’t work, increase the 256 to a bigger number. It is important that the -Xmx parameter comes before the -jar parameter, so that Java knows it is a parameter to the JVM and not to the ImageSizer.
  • When the image is not the proper proportion (which will be nearly all the time), it will crop from the middle of the image. In many cases, this will be a less-than-ideal cropping. If that happens, you should crop the image the way you want it cropped first. (The tool will still help you out because removing the middle of an image is much more tedious.)
  • Your monitors must be of equal resolution.
  • Supported file types are .jpg, .png, and (I think) .bmp and .gif. (I’ve only tested jpg and png myself though.)
  • Output file will always be .png format, even if a different extension is used on output file. This is important because a lossy compression can cause some pixels to “bleed” between the monitors.
  • There is only support for two-monitor setups.
  • If you want to modify the code, feel free to do so. You can even redistribute if you want, just be sure to leave my name and URL in the comments and help info. The source is included in the jar file (open it as a zip file). There are only two Java files.
  • There is a good chance there are some bugs, as this was written in two evenings, with a fourteen-month-old competing with the computer for my attention. The vast majority of that time was spent trying to figure out how to use the Java image libraries. I probably could have written this in PHP in an hour, but I didn’t want to use PHP from the command line, and I didn’t want to have to upload large images.

  1. Yes, these monitor images are stolen from Windows XP display settings. 


CharlotteGigs.net

Warning: I wrote this blog in 2009. That is a long time ago, especially on the internet. My opinions may have changed since then. Technological progress may have made this information completely obsolete. Proceed with caution.

CharlotteGigs.net is a mostly worthless spam machine that masquerades as a local job board. I signed up for their site when I was looking for a job, and now I can’t seem to get their junk mail to stop coming. I have clicked the “unsubscribe” link at the bottom of their spam several times. I continue to get this message upon doing so:

Your request to update your email options has been received and is being processed. Please note that it may take up to 10 days for the changes to take effect as there may be email messages already in progress.

Protip: If you have to show a message like this to your users, you are doing something wrong. Come on guys, ten days?? What are you doing, writing the request on a notarized letter and mailing it to Nigeria?


Some thoughts on programming style

Warning: I wrote this blog in 2009. That is a long time ago, especially on the internet. My opinions may have changed since then. Technological progress may have made this information completely obsolete. Proceed with caution.

Time to discuss something controversial that leads many geeks to commit acts of heinous violence. I’m talking about programming style!

So there are three basic ways to write if/elseif/else statements in most languages with C-like syntax:

Style A

if(condition1)
  statement1;
else if (condition2)
  statement2;
else
  statement3;

Style B

if(condition1) {
  statement1;
} else if (condition2) {
  statement2;
} else {
  statement3;
}

Style C

if(condition1)
{
  statement1;
}
else if (condition2)
{
  statement2;
}
else
{
  statement3;
}

Personally, I go for the most readable and maintainable code, so I use Style A iff all conditions and statements are trivial (by which I mean, they are short and fit on one line). Otherwise I use Style C. (Which you can see, for example, in that gradient-generator source I posted a few weeks ago.)

I’ve posted on my preference for Style C over Style B before, and I’m not going to focus too much on that here today. However, I continue to see Style B promoted as the universal, be-all end-all solution. It is recommended by Sun for Java, and by Zend for PHP.

The argument for preferring Style B over Style A usually goes something like this:

What if you come along and add a new line?

if(condition1)
  statement1;
else
  System.out.println("Condition1 failed!");
  statement2;

Now statement2 gets executed everytime!

The argument makes sense from an academic standpoint, but I am pretty sure this almost never ever happens in practice. The reason for this is that anyone who has been programming for more than a month will immediately see that this code won’t work as designed. It is a glaring bug that jumps out at you. It is nearly impossible to overlook! (Again, this is all assuming that the conditions and statements are all trivial.)

Now, for the last four and a half years my job has been primarily to fix bugs in a huge body of code, very little of which was written by me. For the last two and a half years, in particular, I’ve been the guy who looks at build traces and unit test results from the previous night. And when there are build or test errors, I have to look at recently changed code and decide who is responsible. This means I have seen most of the errors made by a group of about fifty or so programmers. That is to say, real-world errors made by real programmers, not hypothetical errors that might be made by a theoretical programmer. So I think I am reasonably well-qualified to have a strong opinion on the matter.

With that in mind, I’ve never seen an error that was due to the use of Style A for trivial statements. I have seen some downright ugly code that used Style A inappropriately, with conditions that were ten lines long. And I’ve seen ugly code that has braces on the if block but not the else block (or vice-versa). And I have seen several errors in Style B or Style C that result from intermingling of tabs and spaces. This happens because simple editors like vi and Notepad render tabs that are up to 8 characters wide (per spec, I might add), but advanced editors usually break spec in favor of user-friendliness, rendering tabs at 2 or 4 characters wide (or whatever the user sets them to). So if code was written using 4-character tabs in Visual Studio, then new code is added by someone using spaces in vi, and this happens back and forth a few times, you get indentation that jumps all over the place. This is where I think Style C is better than Style B, because it is easier to find the matching open-brace because usually the opening and closing braces are written by the same developer with the same indentation level, even if the code between the braces jumps all around. Also, with Style B, at a glance the code looks like indentation is wacky, since you have to actually read the previous line (or scan to the right end of the previous line) to find out if the developer actually intended the indentation to increase there, or if someone just increased indentation because they were using a different editor.

You can tell me why you disagree with me, and I am fully aware that there will never be agreement on this point; however, I’ll continue to avoid Style B until my pay is docked for it. Someone has to stand up for what is right.


Something I've learned about spam

Warning: I wrote this blog in 2008. That is a long time ago, especially on the internet. My opinions may have changed since then. Technological progress may have made this information completely obsolete. Proceed with caution.

It’s been a while since I implemented a spammer’s honeypot on this blog. It has been extremely effective, so much so that I disabled the captcha. All I do is put a hidden form before any blog posts are displayed. Humans never see it, but spambots all see it, and apparently they are configured to submit spam to the first form on the page. In fact the only spam that has gotten through in the last year has been spam that submitted to all forms on the page, not just the first one. (I think this just happened once though.)

Fast-forward to a few days ago, I noticed that the excerpt of a page that Google shows displays the hidden comment submission form. This doesn’t particularly matter, but I’d prefer it not be there. So I added a check on useragent, and if it appears to be a search engine bot the honeypot is not displayed. Well apparently spammers use a two-step process. First they scan for blogs with forms while pretending to be googlebot. Then they submit to those forms pretending to be a normal user’s browser (usually IE 5.5).

I know this because I got about fifty spam comments in the last two days. If they were scanning the page with user agent reported as IE 5.5, they would have still seen the honeypot. But the comments were submitted with user agent of IE 5.5. Anyway, I’ve gone back to printing the honeypot for everyone, but only for the homepage. Any permalink pages will not have the honeypot. I’m pretty sure spammers don’t bother to go to the permalink pages, and search bots should only be indexing the permalinks. Hopefully, both problems are solved. If not, I’ll have to go back to a more fragile solution (something requiring Javascript, something requiring cookies, or even reinstating captchas).

Or maybe the spammers were just trying to wish me a happy twenty-seventh birthday by flooding my site with links to porn.


Bug report

Warning: I wrote this blog in 2008. That is a long time ago, especially on the internet. My opinions may have changed since then. Technological progress may have made this information completely obsolete. Proceed with caution.

A bug report that came in from a customer a while back:

I found a fully reproducible scenario. But the results are not the same all the times.

I’m pretty sure those two sentences contradict one another.


What's wrong with special characters?

Warning: I wrote this blog in 2008. That is a long time ago, especially on the internet. My opinions may have changed since then. Technological progress may have made this information completely obsolete. Proceed with caution.

Here is a message I got after logging into a website recently:

**** NOTE **** Using a colon (“:”) in your password can create problems when logging in to Banner Self Service. If your password includes a colon, please change it using the PWManager link below.

Protip: If you are designing any kind of login/authentication system and you find that you need to give users a warning similar to this, you are doing something wrong.

On a much more nitpicky side note, why not just make “PWManager” or “using the PWManager” link to PWManager? To their credit, at least they didn’t say “by clicking the PWManager link below.”


A simple solution to cached CSS files

Warning: I wrote this blog in 2008. That is a long time ago, especially on the internet. My opinions may have changed since then. Technological progress may have made this information completely obsolete. Proceed with caution.

I’ve come up with a very simple solution to the problem of browser-cached CSS files. What I mean by this is: when you update the CSS which manages your website’s presentation, it will take a while before some visitors actually see those changes. The reason, of course, is that browsers (this is at least true of IE and Firefox) will cache CSS files pretty aggressively, without checking very often to see if they have been updated. Usually refreshing the page will solve this, but most visitors aren’t going to care enough to do this. Meanwhile, your site will look pretty broken to them (especially if you’ve done something like styled a list so that it looks like a horizontal toolbar instead of a bulleted list, for example).

So here’s the very simple solution. Add the following rule to your root .htaccess file:

RewriteRule ^(.*).[d].css$ $1.css [L]

I’m assuming that you have a common include file or template or something which prints things like the page header. If so, whenever you update your CSS file (say, style.css), you update the link tag in your header to use style.0.css. This will look to the browser like it is a different file from style.css, so it will download it again. But Apache is really just loading the same CSS file through the magic of URL rewriting—you’re just ensuring that the user picks up your recent changes. You can repeat the process the next time you tweak your CSS, just change the header to style.1.css and so on.


Macrolicious

Warning: I wrote this blog in 2008. That is a long time ago, especially on the internet. My opinions may have changed since then. Technological progress may have made this information completely obsolete. Proceed with caution.

I recently came across a clever way of writing preprocessor macros, and I figured that I would share.

Let’s say that for some reason you need to write a macro: MACRO(X,Y)1. You want this macro to emulate a function call in every way2.

Example 1: This should work as expected.

if (x > y)
  MACRO(x, y);
do_something();

Example 2: This should not result in a compiler error.

if (x > y)
  MACRO(x, y);
else
  MACRO(y - x, x - y);

Example 3: This should not compile.

do_something();
MACRO(x, y)
do_something();

The naïve way to write the macro is like this:

#define MACRO(X,Y)                       
cout << "1st arg is:" << (X) << endl;    
cout << "2nd arg is:" << (Y) << endl;    
cout << "Sum is:" << ((X)+(Y)) << endl;

This is a very bad solution which fails all three examples, and I shouldn’t need to explain why.

Now, the way I most often see macros written is to enclose them in curly braces, like this:

#define MACRO(X,Y)                         
{                                          
  cout << "1st arg is:" << (X) << endl;    
  cout << "2nd arg is:" << (Y) << endl;    
  cout << "Sum is:" << ((X)+(Y)) << endl;  
}

This solves example 1, because the macro is in one statement block. But example 2 is broken because we put a semicolon after the call to the macro. This makes the compiler think the semicolon is a statement by itself, which means the else statement doesn’t correspond to any if statement! And lastly, example 3 compiles OK, even though there is no semicolon, because a code block doesn’t need a semicolon.

The solution is kind of clever, I thought:

#define MACRO(X,Y)                         
do {                                       
  cout << "1st arg is:" << (X) << endl;    
  cout << "2nd arg is:" << (Y) << endl;    
  cout << "Sum is:" << ((X)+(Y)) << endl;  
} while (0)

Now you have a single block-level statement, which must be followed by a semicolon. This behaves as expected and desired in all three examples. I have noticed this macro pattern before, but I never really thought about why it was written this way. Mainly because I don’t often write macros to begin with.


  1. You should first ask yourself why you can’t just write a regular function and declare it inline, so that the compiler will do the work for you. I’m going to assume there is some good reason why you must use a macro. 

  2. Every way, that is, except that it can’t return a value. That gets much trickier and involves heavy abuse of the ?: operator, if it is even possible at all. 


Lunar eclipse of aught-eight

Warning: I wrote this blog in 2008. That is a long time ago, especially on the internet. My opinions may have changed since then. Technological progress may have made this information completely obsolete. Proceed with caution.

Lunar eclipse, 45 minutes prior to totality

While looking for information on yesterday’s lunar eclipse, I found NASA’s solar eclipse website which has maps of every solar eclipse from 2000 BC to 3000 AD in 20-year blocks. I took a look through these, it seems like I only get three chances to see a solar eclipse in my lifetime, assuming: 1) I live in this general area of the planet my whole life; 2) I don’t want to travel more than 5-6 hours to see one; and 3) I live to be at least 96 years old.

The first opportunity has already passed by: a partial solar eclipse on May 30, 1984 which passed right over my hometown. I don’t remember it; I guess I was too two to care.1

However, on Monday, August 21, 2017, a total solar eclipse will pass by very close to where I currently live. I’m thinking on that day I’ll take the day off work and head out to somewhere in the western North Carolina mountains to see the eclipse. If anyone wants to join me then go ahead and mark your calendar.

Path of August 21, 2017 total solar eclipse

The third opportunity for me to see an eclipse will be May 11, 2078. I will be 96.5 years old then, so I’m not sure if I’ll still care (assuming, of course, that I’m still alive, which is statistically improbable).

One last thing that I couldn’t think of a way to segue into: there is an interesting story about how Christopher Columbus used a lunar eclipse to save his life. Sufficiently advanced technology is indistinguishable from magic.


  1. I seem to recall an eclipse happening when I was in middle school. I know it didn’t get dark or anything, but I think it got a little bit dimmer outside. This must have been the May 10, 1994 partial solar eclipse, although the path of the eclipse was several hundred miles from North Carolina. 


Array-casting in Java

Warning: I wrote this blog in 2007. That is a long time ago, especially on the internet. My opinions may have changed since then. Technological progress may have made this information completely obsolete. Proceed with caution.

Since I haven’t posted anything this week, I figured I’d share something annoying I discovered in Java: you can’t assume that you can put an object of type T into a T array (unless you happen to know that T is declared as a final class).

Take for example this code, which tries to put an Integer (which is an Object) into an array of Objects:

public static void main(String[] args)
{
  Object[] objects = new String[2];
  objects[0] = "ABC";
  objects[1] = new Integer(5);
}

This code compiles with no problem but when run it gives a runtime error on the objects[1]= line. But if the array were declared as new Object[2]; it would run with no complaints.

The problem is that you’re allowed to cast an array of type T to an array of a super-type of T, but you don’t really have an array of the super-type. I imagine they decided to allow this because of the usefulness of casting arrays to super-types for reading the data. But it opens up a whole new set of bugs that most of the time you wouldn’t even think to check for (especially if the array is declared in someone else’s code).

Apparently C# has controversially included the same feature.