Archive for the ‘HOW-TOs’ Category.

Image resolution in pixels vs DPI

When working with the print shop to create a poster out of a 3174 x 2153 pixel digital photo, I managed to get completely confused about DPI (dots per inch). I read a blog post called The Myth of DPI to educate myself, but that seemed to muddy the water even more for me. I must have been having a bad week because now the relation between pixel resolution and DPI is crystal clear:

pixels = inches * dpi

I wanted to print a poster that was 36″ wide, meaning that the DPI of the printout would be 88 (dpi = 3174 / 36 = 88).

Obviously, the more ink dots per inch you have, the crisper the image will look on a printed page. The printer recommended that I have 300 dpi to retain the quality of the image. What they didn’t make clear to me was that in order to have a 36″ wide poster at 300 dpi, I would need an image that was 10800 x 7200 pixels.

Adding to my confusion is that DPI is apparently part of the JPEG metadata. This means that you can change the DPI to whatever value you want. The key point is that raising the DPI reduces the printable image size, and lowering the DPI increases the printable image size.

All of this is spelled out in the The Myth of DPI, but for whatever reason I wasn’t getting it. Once I finally understood, I decided to bite the bullet and print the size I wanted, meaning that I would have to deal with 88 dpi. I think the resulting poster looks great. I mean, you wouldn’t put it up in an Ansel Adams gallery, but I don’t see any pixelation and it will be viewed mostly from afar. Time to frame this puppy and call this project done!

How to compile bandwidthd 2.0.1 on OpenBSD 4.3

I ran into numerous problems when trying to compile bandwidthd 2.0.1 on OpenBSD 4.3. The first problem was that, even though I had installed all the dependencies via ports, ./configure was still erroring out with:

checking for png_read_info in -lpng... no
configure: error: Bandwidthd requires but cannot libpng

Hunting around the web, I managed to get past that error, but then ran into this:

checking for gdImageCreate in -lgd... no
configure: error: Bandwidthd requires but cannot find libgd

The solution to both of these problems is this:

./configure LDFLAGS=-lz -x-libraries=/usr/X11R6/lib

I thought I was good to go at that point, but a make resulted in this problem:

Graph cycles through conf.l.c

`all' not remade because of errors.

I banged my head on this for some time before turning to the OpenBSD misc mailing list. Philip Guenther pointed me in the right direction:

The makefile is either buggy or assumes a non-POSIX make. Try it again with ‘gmake’. If you still get errors, yell at the bandwidthd authors.

I grabbed gmake from ports and voilà, success!

Volume discounts with PayPal Merchant Services

You’re probably not going to like this solution very much.

To set the scene, PayPal’s “Merchant Services” contains a fairly straightforward webapp to generate “Buy Now” and other such buttons. When we needed to sell a product at work, I figured that the steps would be as simple as:

  1. Generate the button
  2. Slap it on our website

Unfortunately for me, we were offering a volume discount (AKA, bulk rate) so that the price of the item was different depending on the quantity. After much mucking around in help pages and documentation, I found the “solution” in the PayPal Developer Community forums: Volume Discount with Shopping Carts

Long story short:

  1. Don’t use PayPal’s button generator
  2. Download the zipped HTML file referenced in the forum
  3. Read the HTML file and its source, giving you the knowledge to:
    1. Add some generically-written javascript functions to your site
    2. Create a custom HTML button (i.e., not generated by PayPal)
    3. Add the HTML inputs and inline javascript needed to drive the functions
  4. Tell your bookkeeper to double-check the payment amounts because any tech-savvy person could submit a form with whatever prices they please

The problem is that when using your own custom buttons, PayPal cannot do any validations on their end. You send them item names and amounts, and they’ll happily charge the customer for whatever happens to come across the wire. From my limited research, I think you can do this more cleanly if you implement your own shopping cart, and interface with PayPal in a more secure way.

But for the “simple” stuff, the best way to get started would be by perusing the PayPal Developer Central’s Simple Integration section. I found the HTML Variables for Website Payments Standard to be particularly useful. It really wouldn’t be that hard for PayPal to implement volume discount functionality on their end, but I suspect that maybe it’s something they are trying to sell in a “Pro” version.

sh: read: -p: no coprocess

Just thought I’d throw this out there since I don’t see many google hits on it. The problem (on OpenBSD 4.4):

$ read -p "Enter input: " MYVAR
sh: read: -p: no coprocess

Oh, of course, “no coprocess”! Surely, if I can somehow just add a “coprocess” then my read command will work… </sarcasm>

Anyway, I dug through info sh to see how the read command works on my OpenBSD system. Apparently one needs to format the command like this:

read MYVAR?"Enter input: "

jQuery: disable the submit button, but still send the button’s value

Solving the old user-hits-the-submit-button-twice problem is fairly easy using JavaScript and even easier using jQuery. Setting up a sequence like the following is no problem:

  1. User clicks the submit button
  2. Button becomes disabled
  3. The values of the form’s inputs are submitted

My problem is that disabling the submit button causes its value to not submit. Apparently no one else on the planet uses the submit button’s value because none of my Google searches revealed anyone caring about this in the context of using JavaScript to disable the submit button.

No doubt my custom framework could be better designed, but there are a few rare instances when I want to know whether a user submitted a particular form, or even which button in the form they used to fire the submit. If I disable the button, then I don’t get the button’s name/value and thus I lose information about what is happening on the user’s end.

I have two solutions to this problem, the first of which was inspired by Ryan’s comment to my initial draft of this blog entry.

SOLUTION #1: hide the submit button after click

$(document).ready(function() {
  $("input:submit").click(function (event) {
    $(event.target).addClass("Hidden");
    var form = event.target.parentNode;
    var msg = document.createElement("i");
    msg.innerHTML = "PROCESSING...";
    form.insertBefore(msg, event.target.nextSibling);
  });
  $("form").submit(function() {
    $(":submit:not(.Hidden)", this).attr("disabled", "disabled");
  });
});

You will note that I am making use of a CSS class that I’ve called “Hidden”:

.Hidden {
  display: none;
}

Now the sequence of events looks like this:

  1. User clicks the submit button
  2. The click listener runs a function that hides the submit button and replaces it with some italicized PROCESSING… text
  3. The submit listener then disables all other submit buttons
  4. The values of the form’s inputs are submitted, including the newly hidden submit button

SOLUTION #2: copy the name/value to a hidden element

This is my original, hacky solution:

$(document).ready(function() {
  $("input:submit").click(function (event) {
    var $submitName = event.target.name;
    var $submitValue = event.target.value;
    var $form = event.target.parentNode;
    $($form).append("<input type=\"hidden\" name=\"" + $submitName + "\" value=\"" + $submitValue + "\">");
  });
  $("form").submit(function() {
    $(":submit",this).attr("disabled", "disabled");
  });
});

Can you see what horrors I’ve wrought? Now the sequence of events looks like this:

  1. User clicks the submit button
  2. The click listener runs a function that copies the name/value of the clicked submit button to a hidden input which is appended to the form
  3. The submit listener then disables the submit button
  4. The values of the form’s inputs are submitted, including the new hidden input
  5. To the rest of my code, it appears as if the submit button’s name/value came through with everything else

Now don’t be stingy, man. Pass the data, dude.

Slow printing to Lexmark C522 from OS X 10.4

After a user complained that a 28-page PowerPoint document was taking an hour to print on our networked Lexmark C522, I narrowed the problem down to OS X 10.4 (in my case, 10.4.11).

Solution: use this PPD. In other words:

  1. Save the PPD to your desktop
  2. Go into System Preferences and remove the printer
  3. Add the printer back, specifying the PPD on your desktop as the driver instead of whatever OS X wants to use

My understanding is that the PPD I’ve linked to is supplied by Lexmark – perhaps they simply haven’t updated the 10.4.x driver on their website.

Using EDID data in xorg.conf

I have two Hanns-G JW199D (19″ 1440×900) LCDs connected to an nVidia GeForce 8400 GS video card. They worked great until I upgraded from openSUSE 10.3 to 11.0; Xorg seemed to have problems configuring the LCD connected to the video card’s VGA port. The image was cropped and at an odd, fuzzy resolution, but the LCD on the DVI port was fine.

I examined /var/log/Xorg.0.log and found this:

(WW) NVIDIA(GPU-0): Unable to read EDID for display device CRT-0

I was fairly certain that this had always been the case, and that the monitor in question was being configured from the “Monitor” and “Modes” sections. But after fooling around with modeline generators and tweaking xorg.conf, I was unable to create a configuration that would give back my 1440×900 display.

Finally I thought, can’t I just apply the EDID data from the working monitor to the problem monitor?

I fired up nvidia-settings and used that to dump a binary copy of the EDID. Then I grabbed read-edid and ran the parse-edid which conveniently generated a “Monitor” section for me. I integrated this output into xorg.conf and I was back in action!

PHP zlib.output_compression fails to set Content-Encoding

This is what the PHP docs say about the zlib.output_compression INI directive:

Whether to transparently compress pages. If this option is set to “On” in php.ini or the Apache configuration, pages are compressed if the browser sends an “Accept-Encoding: gzip” or “deflate” header. “Content-Encoding: gzip” (respectively “deflate”) and “Vary: Accept-Encoding” headers are added to the output. In runtime, it can be set only before sending any output.

Seems pretty straightforward, except that enabling this directive on an openSUSE 10.3 server (and an openSUSE 10.2 server) resulted in a bunch of gibberish as output. Meanwhile, the compression worked just fine on my MacPorts-enhanced MacBook.

After flailing around on Google and php.ini, I eventually eliminated SSL and the firewall as reasons for the problem. During this process I wasted a good amount of time on this bug. Basically, the docs say that you can set zlib.output_compression in your script at runtime, but in reality it doesn’t work.

I finally got down to business with Live HTTP Headers and figured out that enabling zlib compression on my openSUSE servers certainly compressed the content, but did not send the requisite “Content-Encoding: gzip” response header. Sending the header manually within my script (e.g. header("Content-Encoding: gzip");) would correctly turn the gibberish into uncompressed form.

Having already spent hours mucking around with this, I went with a quick and dirty solution:

ob_start('ob_gzhandler');
echo $page->toHtml();
ob_end_flush();

I hunted around Google for this problem, but only found PHP4 references from years ago. Maybe it’s time to ditch openSUSE on my servers… Ubuntu LTS might hit the spot.

TortoiseSVN “connection closed unexpectedly”

This burned several hours of my time so I thought I’d add this post to the others that I found on the Intertron.

I had debugged every possible angle when trying to get a Vista machine to checkout a repo from an svn+ssh server. At last I figured it had to be a subversion client-server version problem, rather than an issue with the SSH keys, and so it was.

For reference, I’m using TortoiseSVN 1.5.5 and the server is running openSUSE 11.0′s subversion-1.5.0-96.1 package.

The solution, as many have stated, is to downgrade to TortoiseSVN 1.4.8.

CRT monitor recycling and disposal in Gainesville, FL

Problem: you have upgraded your computer monitors to LCDs and want to get rid of your old CRTs in a way that won’t dump a bunch of lead into the environment. Also, you live in Gainesville, FL where there is no recycling center that takes such things.

Solution: bring them to the Hazardous Waste Collection Center. You may need to pay a fee depending on the number of monitors.

Research: I only skimmed The Importance of Comprehensive Policy to Promote Safe CRT Recycling, but there are some interesting things in there. The difficulties with CRT recycling are about what you’d expect; quoting from the paper:

A CRT product is bulky and heavy to transport, it contains a high amount of toxic materials, and most of its weight is in low valued materials for recycling (leaded glass and plastics).

Other options: I wouldn’t put much stock in these options, but they might give you some ideas.

  • Thrift stores (e.g. Goodwill, Salvation Army) – at one point the Salvation Army took six (6) CRTs off my hands. However, I went there the other day and was told they they’ve got about 150 of them sitting in storage and weren’t going to take any more.
  • Dignity Project – talking on the phone to them, I was told they’ll take 17″ CRTs, but nothing larger than that.