Wednesday, November 12, 2008

Retrieving XML, HTML and JSON with JQuery

I've been using JQuery in a project and recently discovered that code that worked fine under Firefox3 was failing under Firefox2 and IE6. The issue turned out to be my misunderstanding of how to properly retrieve data from an ajax call.

My code expected a proper XML object. I was using the jquery $.load() method mostly for its simplicity. Under FF2 and IE6, instead of getting an XML object, I was getting text which jquery was parsing as xml. The docs claim you'll get inconsistent results in this situation and they were absolutely right.

To resolve this, I used the $.post() method instead where the data type of the expected results can be specified. I wrote this small javascript class to retrieve xml, html and json data:

function Fetch() {
this.result = null;
this.Xml = function(params) {, 'xml');
this.Html = function(params) {, 'html');
this.Json = function(params) {, 'json');
}; = function (params, dataType) {
var result = null;
var response = $.post("service.php",
function(data) {
result = data;
this.result = result;

So, Fetch.Xml() returns an actual XML object rather than inconsistently parsed text. FF2 and IE6 now work fine.

Monday, August 25, 2008

A rainy morning in Paris...

Joseph and I boarded our flight Thursday evening ready for a break. The trip that seemed like ages away when we planned it was here. I had considered following the latest fad to fight jet lag: pre-flight fasting. But some digging revealed that the study being quoted everywhere was actually done on mice, and the results had never been shown to occur in humans. Air France provided a very edible meal with some very drinkable wine. So mice be damned. I ate.

We passed the time watching a variety of movies and frequently switching back to the "Geo" channel where the plane's current position on a map and vital flying statistics were displayed. Of course I tried to sleep, but that is usually an elusive goal for me on a plane. The passenger behind us snored away, showing off his effortless command of attaining the unconscious state.

"Morning" arrived much to soon. The excitement of arriving helped slightly to fool the body into overlooking the fact that it is really two-thirty in the morning. Outside, the Paris morning was gray and rainy. We were in the very back of the plane so our liberation from coach would take a while. Another passenger was a bit less patient and was trying to work his way through the crowded aisle to move to the front of the plane. He was challenged by an older man who called him an asshole. I thought I was about witness some air rage as the two faced off. Luckily, angry looks were enough to dissipate the excess testosterone.

The rain drizzled down as we walked down the covered steps off the plane. We dashed across the tarmac over to one of the buses waiting to take us into the airport. We navigated Charles de Gaulle looking for the exit so we could transfer to Orly to catch our connecting flight to Sevilla.

We found passport control and got in line. It moved quickly and soon I got my stamp and passed through. I waited for Joseph. The officer seemed to be explaining something to him and pointing back from where we came. I joined in at that point and it seemed there was some visa issue about changing airports since Joseph has a Colombian passport. I wasn't clear on all the details, but the upshot was that we need to talk to Air France about a temporary transit visa. We had plenty of time to make our flight at Orly, so this seemed like a minor annoyance.

We went back towards the gates to the Air France desk. We needed to pass through security again, but since we didn't have a boarding pass, we weren't really allowed to go back in. We explained the situation to the officials and waited while an Air France agent was dispatched.

The agent arrived and we explained the situation again. He looked a little worried and asked how long it was until our next flight. He took our passports and disappeared. We still had plenty of time so I was still upbeat. I hadn't realized it yet, but we were in limbo at this point. We were in the stateless land between the airport security checkpoint and passport control. The lack of any windows and the institutional gray should have tipped me off.

Our travel documents were being whisked around the airport while we waited in limbo. Some feelings of doubt started to creep in but this silliness would soon be forgotten after our vacation started in earnest. After twenty minutes or so -- time had ceased to have any meaning -- the agent returned. His discussion with the passport officer did not yield good news. Joseph did not have the proper visa to be traveling in Europe and we would have to return to Philadelphia. Denial immediately set in. This absolutely could not be true. Joseph had checked numerous times with the Spanish consulate in New York and Washington DC and had received the same answer each time: his Colombian passport and his American green card were all he needed. Whoever provided this answer though, must have been on crack since it was simply not true.

The agent was patient while we nurtured our denial. Frantic phone calls to family in the U.S. got us embassy phone numbers in Paris. We spoke with officials who confirmed the visa problems and had no help they could offer. As the inevitable was forcing itself upon us, the agent expressed his surprise that we were even allowed on the plane without the proper documentation. Pardon? Excuse me? We had been given misinformation from the consulate AND the gate agent in Philadelphia had slipped up and allowed us through!

The inevitable crept in on us. Joseph urged me to continue on our trip while he returned home, but I couldn't imagine the trip without him. Defeated but still a little incredulous, we acquiesced and the agent booked our seats on the return flight home. Waiting at the gate forced the reality to sink in a bit more.

The rain continued to fall outside, and the gray light and the exhaustion mixed to create a starkness and clarity to the scene around us. A woman waiting for the same flight sat at the gate with a cough that made tuberculosis sufferers sound like timid throat clearers. We kept a safe distance until boarding time. We were first in line, but by some strange coincidence, Joseph was randomly selected for the "additional" security check. I waited while his bag was opened and he was wanded with a metal detector.

We took our seats on the plane and began to settle in for our long flight back. My heart filled suddenly with panic and then dread as I saw the coughing woman and her companion approach and take the seats immediately behind us. A completely different sensation hit me like a brick wall when she raised her arms to lift her bags into the overhead compartment. Now I had two reasons to fear taking a breath.

An involuntary prayer escaped me while passengers trickled into the plane. I asked the flight attendant if the flight was very full. She cheerfully told me it wasn't and changing seats would not be a problem. At least this all wasn't some form of godly punishment. We moved forward several rows until I imagined we were out of reach of coughing woman's contagion.

The flight back was uneventful. I had a few short naps but no real rest. The "Geo" channel which previously was full of excitement and promise now felt like personal mockery as the plane icon crept slowly back to Philadelphia. We made a few loops on the screen just outside New Jersey before air traffic cleared us for landing.

We were back on the ground again on our usual side of the Atlantic much sooner than we had originally had planned. I filled out the customs card and wrote in France for countries visited. I was mentally preparing for the officer's question, "how long were you in France?" The answer of "four hours" seemed a bit flippant without further explanation.

Questions asked and answered, we were now legally back inside the U.S. at about four-thirty in the afternoon. Twenty-four hours earlier, we had just arrived at the Philadelphia airport to leave for our trip. Now we were back where we had started. One vacation goal was certainly attained. This would definitely be one unforgettable trip.

Monday, March 17, 2008

Converting PDF to bitmaps

I've been trying to use ImageMagick's "convert" utility to convert a PDF image into constituent bitmap images -- for OCR and other purposes. If I just run:
convert file.pdf file.tiff
I end up with a really large mostly blank page with a very small bitmap in the lower left corner. That tiny bitmap is also very blocky when the size is blown up. So here is how to fix this problem:

The Difficulty Way
  1. Use the -density option to specify the DPI of the resulting bitmap. This will get rid of the blockiness, but will also make the entire image very large -- including the large blank areas.
  2. Use the -crop option to crop out the tiny portion of the image that we actually want. We'll need to do a little math to get the exact numbers. The origin for the page is the top left corner. Positive number shift right and down. So we need to compute the Y offset to get just the bottom of the page. I haven't seen a way to reorient the coordinate system of the page to make this easier.
In my example, the original image was 2900x3800. You can use ImageMagick's "identify" utility to find out what the native image sizes are within the pdf. When I used convert -density 300 without any cropping the resulting image size was 12083x15833. I just want the lower 3800 pixels so I have to offset by 15833-3800 or 11933 pixels. So the conversion command is:
convert -density 300 -crop 2900x3800+0+11933 file.pdf target.tif
Well, I tried this and doesn't work exactly but is close. It seems that the conversion is using some scaling factor that I can't find. Fortunately, there is a better way.

The Easy Way

Use the -density option along with the -page option to specify page size. This crops the page correctly if you use a page size (e.g., letter, A4, etc.) whose aspect ratio matches your page. In these case, the final conversion command is:
convert -density 300 -page letter file.pdf target.tif
We can also use the "-compress lzw" option to compress the file when we are using TIFF for our bitmap format.